199bfc35243bc810e59ef0c0f39bd79eb59030ab2Ecco Park/*
299bfc35243bc810e59ef0c0f39bd79eb59030ab2Ecco Park *
399bfc35243bc810e59ef0c0f39bd79eb59030ab2Ecco Park *  Copyright (c) 2013, The Linux Foundation. All rights reserved.
499bfc35243bc810e59ef0c0f39bd79eb59030ab2Ecco Park *  Not a Contribution.
599bfc35243bc810e59ef0c0f39bd79eb59030ab2Ecco Park *
699bfc35243bc810e59ef0c0f39bd79eb59030ab2Ecco Park *  Copyright 2012 The Android Open Source Project
799bfc35243bc810e59ef0c0f39bd79eb59030ab2Ecco Park *
899bfc35243bc810e59ef0c0f39bd79eb59030ab2Ecco Park *  Licensed under the Apache License, Version 2.0 (the "License"); you
999bfc35243bc810e59ef0c0f39bd79eb59030ab2Ecco Park *  may not use this file except in compliance with the License. You may
1099bfc35243bc810e59ef0c0f39bd79eb59030ab2Ecco Park *  obtain a copy of the License at
1199bfc35243bc810e59ef0c0f39bd79eb59030ab2Ecco Park *
1299bfc35243bc810e59ef0c0f39bd79eb59030ab2Ecco Park *  http://www.apache.org/licenses/LICENSE-2.0
1399bfc35243bc810e59ef0c0f39bd79eb59030ab2Ecco Park *
1499bfc35243bc810e59ef0c0f39bd79eb59030ab2Ecco Park *  Unless required by applicable law or agreed to in writing, software
1599bfc35243bc810e59ef0c0f39bd79eb59030ab2Ecco Park *  distributed under the License is distributed on an "AS IS" BASIS,
1699bfc35243bc810e59ef0c0f39bd79eb59030ab2Ecco Park *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
1799bfc35243bc810e59ef0c0f39bd79eb59030ab2Ecco Park *  implied. See the License for the specific language governing
1899bfc35243bc810e59ef0c0f39bd79eb59030ab2Ecco Park *  permissions and limitations under the License.
1999bfc35243bc810e59ef0c0f39bd79eb59030ab2Ecco Park *
2099bfc35243bc810e59ef0c0f39bd79eb59030ab2Ecco Park */
2199bfc35243bc810e59ef0c0f39bd79eb59030ab2Ecco Park
2299bfc35243bc810e59ef0c0f39bd79eb59030ab2Ecco Park/******************************************************************************
2399bfc35243bc810e59ef0c0f39bd79eb59030ab2Ecco Park *
2499bfc35243bc810e59ef0c0f39bd79eb59030ab2Ecco Park *  Filename:      hw_ar3k.c
2599bfc35243bc810e59ef0c0f39bd79eb59030ab2Ecco Park *
2699bfc35243bc810e59ef0c0f39bd79eb59030ab2Ecco Park *  Description:   Contains controller-specific functions, like
2799bfc35243bc810e59ef0c0f39bd79eb59030ab2Ecco Park *                      firmware patch download
2899bfc35243bc810e59ef0c0f39bd79eb59030ab2Ecco Park *                      low power mode operations
2999bfc35243bc810e59ef0c0f39bd79eb59030ab2Ecco Park *
3099bfc35243bc810e59ef0c0f39bd79eb59030ab2Ecco Park ******************************************************************************/
3199bfc35243bc810e59ef0c0f39bd79eb59030ab2Ecco Park#ifdef __cplusplus
3299bfc35243bc810e59ef0c0f39bd79eb59030ab2Ecco Parkextern "C" {
3399bfc35243bc810e59ef0c0f39bd79eb59030ab2Ecco Park#endif
3499bfc35243bc810e59ef0c0f39bd79eb59030ab2Ecco Park
3599bfc35243bc810e59ef0c0f39bd79eb59030ab2Ecco Park#define LOG_TAG "bt_vendor"
3699bfc35243bc810e59ef0c0f39bd79eb59030ab2Ecco Park
3799bfc35243bc810e59ef0c0f39bd79eb59030ab2Ecco Park#include <sys/socket.h>
3899bfc35243bc810e59ef0c0f39bd79eb59030ab2Ecco Park#include <utils/Log.h>
3999bfc35243bc810e59ef0c0f39bd79eb59030ab2Ecco Park#include <sys/types.h>
4099bfc35243bc810e59ef0c0f39bd79eb59030ab2Ecco Park#include <sys/stat.h>
4199bfc35243bc810e59ef0c0f39bd79eb59030ab2Ecco Park#include <signal.h>
4299bfc35243bc810e59ef0c0f39bd79eb59030ab2Ecco Park#include <time.h>
4399bfc35243bc810e59ef0c0f39bd79eb59030ab2Ecco Park#include <errno.h>
4499bfc35243bc810e59ef0c0f39bd79eb59030ab2Ecco Park#include <fcntl.h>
4599bfc35243bc810e59ef0c0f39bd79eb59030ab2Ecco Park#include <dirent.h>
4699bfc35243bc810e59ef0c0f39bd79eb59030ab2Ecco Park#include <ctype.h>
4799bfc35243bc810e59ef0c0f39bd79eb59030ab2Ecco Park#include <cutils/properties.h>
4899bfc35243bc810e59ef0c0f39bd79eb59030ab2Ecco Park#include <stdlib.h>
4999bfc35243bc810e59ef0c0f39bd79eb59030ab2Ecco Park#include <string.h>
5099bfc35243bc810e59ef0c0f39bd79eb59030ab2Ecco Park#include <termios.h>
5199bfc35243bc810e59ef0c0f39bd79eb59030ab2Ecco Park
5299bfc35243bc810e59ef0c0f39bd79eb59030ab2Ecco Park#include "bt_hci_bdroid.h"
5399bfc35243bc810e59ef0c0f39bd79eb59030ab2Ecco Park#include "hci_uart.h"
5499bfc35243bc810e59ef0c0f39bd79eb59030ab2Ecco Park#include "hw_ar3k.h"
5599bfc35243bc810e59ef0c0f39bd79eb59030ab2Ecco Park
5699bfc35243bc810e59ef0c0f39bd79eb59030ab2Ecco Park/******************************************************************************
5799bfc35243bc810e59ef0c0f39bd79eb59030ab2Ecco Park**  Variables
5899bfc35243bc810e59ef0c0f39bd79eb59030ab2Ecco Park******************************************************************************/
5999bfc35243bc810e59ef0c0f39bd79eb59030ab2Ecco Parkint cbstat = 0;
6099bfc35243bc810e59ef0c0f39bd79eb59030ab2Ecco Park#define PATCH_LOC_STRING_LEN   8
6199bfc35243bc810e59ef0c0f39bd79eb59030ab2Ecco Parkchar ARbyte[3];
6299bfc35243bc810e59ef0c0f39bd79eb59030ab2Ecco Parkchar ARptr[MAX_PATCH_CMD + 1];
6399bfc35243bc810e59ef0c0f39bd79eb59030ab2Ecco Parkint byte_cnt;
6499bfc35243bc810e59ef0c0f39bd79eb59030ab2Ecco Parkint patch_count = 0;
6599bfc35243bc810e59ef0c0f39bd79eb59030ab2Ecco Parkchar patch_loc[PATCH_LOC_STRING_LEN + 1];
6699bfc35243bc810e59ef0c0f39bd79eb59030ab2Ecco Parkint PSCounter=0;
6799bfc35243bc810e59ef0c0f39bd79eb59030ab2Ecco Park
6899bfc35243bc810e59ef0c0f39bd79eb59030ab2Ecco Parkuint32_t dev_type = 0;
6999bfc35243bc810e59ef0c0f39bd79eb59030ab2Ecco Parkuint32_t rom_version = 0;
7099bfc35243bc810e59ef0c0f39bd79eb59030ab2Ecco Parkuint32_t build_version = 0;
7199bfc35243bc810e59ef0c0f39bd79eb59030ab2Ecco Park
7299bfc35243bc810e59ef0c0f39bd79eb59030ab2Ecco Parkchar patch_file[PATH_MAX];
7399bfc35243bc810e59ef0c0f39bd79eb59030ab2Ecco Parkchar ps_file[PATH_MAX];
7499bfc35243bc810e59ef0c0f39bd79eb59030ab2Ecco ParkFILE *stream;
7599bfc35243bc810e59ef0c0f39bd79eb59030ab2Ecco Parkint tag_count=0;
7699bfc35243bc810e59ef0c0f39bd79eb59030ab2Ecco Park
7799bfc35243bc810e59ef0c0f39bd79eb59030ab2Ecco Park/* for friendly debugging outpout string */
7899bfc35243bc810e59ef0c0f39bd79eb59030ab2Ecco Parkstatic char *lpm_mode[] = {
7999bfc35243bc810e59ef0c0f39bd79eb59030ab2Ecco Park    "UNKNOWN",
8099bfc35243bc810e59ef0c0f39bd79eb59030ab2Ecco Park    "disabled",
8199bfc35243bc810e59ef0c0f39bd79eb59030ab2Ecco Park    "enabled"
8299bfc35243bc810e59ef0c0f39bd79eb59030ab2Ecco Park};
8399bfc35243bc810e59ef0c0f39bd79eb59030ab2Ecco Park
8499bfc35243bc810e59ef0c0f39bd79eb59030ab2Ecco Parkstatic char *lpm_state[] = {
8599bfc35243bc810e59ef0c0f39bd79eb59030ab2Ecco Park    "UNKNOWN",
8699bfc35243bc810e59ef0c0f39bd79eb59030ab2Ecco Park    "de-asserted",
8799bfc35243bc810e59ef0c0f39bd79eb59030ab2Ecco Park    "asserted"
8899bfc35243bc810e59ef0c0f39bd79eb59030ab2Ecco Park};
8999bfc35243bc810e59ef0c0f39bd79eb59030ab2Ecco Park
9099bfc35243bc810e59ef0c0f39bd79eb59030ab2Ecco Parkstatic uint8_t upio_state[UPIO_MAX_COUNT];
9199bfc35243bc810e59ef0c0f39bd79eb59030ab2Ecco Parkstruct ps_cfg_entry ps_list[MAX_TAGS];
9299bfc35243bc810e59ef0c0f39bd79eb59030ab2Ecco Park
9399bfc35243bc810e59ef0c0f39bd79eb59030ab2Ecco Park#define PS_EVENT_LEN 100
9499bfc35243bc810e59ef0c0f39bd79eb59030ab2Ecco Park
9599bfc35243bc810e59ef0c0f39bd79eb59030ab2Ecco Park#ifdef __cplusplus
9699bfc35243bc810e59ef0c0f39bd79eb59030ab2Ecco Park}
9799bfc35243bc810e59ef0c0f39bd79eb59030ab2Ecco Park#endif
9899bfc35243bc810e59ef0c0f39bd79eb59030ab2Ecco Park
9999bfc35243bc810e59ef0c0f39bd79eb59030ab2Ecco Park/*****************************************************************************
10099bfc35243bc810e59ef0c0f39bd79eb59030ab2Ecco Park**   Functions
10199bfc35243bc810e59ef0c0f39bd79eb59030ab2Ecco Park*****************************************************************************/
10299bfc35243bc810e59ef0c0f39bd79eb59030ab2Ecco Park
10399bfc35243bc810e59ef0c0f39bd79eb59030ab2Ecco Parkint is_bt_soc_ath() {
10499bfc35243bc810e59ef0c0f39bd79eb59030ab2Ecco Park    int ret = 0;
10599bfc35243bc810e59ef0c0f39bd79eb59030ab2Ecco Park    char bt_soc_type[PROPERTY_VALUE_MAX];
10699bfc35243bc810e59ef0c0f39bd79eb59030ab2Ecco Park    ret = property_get("qcom.bluetooth.soc", bt_soc_type, NULL);
10799bfc35243bc810e59ef0c0f39bd79eb59030ab2Ecco Park    if (ret != 0) {
10899bfc35243bc810e59ef0c0f39bd79eb59030ab2Ecco Park        ALOGI("qcom.bluetooth.soc set to %s\n", bt_soc_type);
10999bfc35243bc810e59ef0c0f39bd79eb59030ab2Ecco Park        if (!strncasecmp(bt_soc_type, "ath3k", sizeof("ath3k")))
11099bfc35243bc810e59ef0c0f39bd79eb59030ab2Ecco Park            return 1;
11199bfc35243bc810e59ef0c0f39bd79eb59030ab2Ecco Park    } else {
11299bfc35243bc810e59ef0c0f39bd79eb59030ab2Ecco Park        ALOGI("qcom.bluetooth.soc not set, so using default.\n");
11399bfc35243bc810e59ef0c0f39bd79eb59030ab2Ecco Park    }
11499bfc35243bc810e59ef0c0f39bd79eb59030ab2Ecco Park
11599bfc35243bc810e59ef0c0f39bd79eb59030ab2Ecco Park    return 0;
11699bfc35243bc810e59ef0c0f39bd79eb59030ab2Ecco Park}
11799bfc35243bc810e59ef0c0f39bd79eb59030ab2Ecco Park
11899bfc35243bc810e59ef0c0f39bd79eb59030ab2Ecco Park/*
11999bfc35243bc810e59ef0c0f39bd79eb59030ab2Ecco Park * Send HCI command and wait for command complete event.
12099bfc35243bc810e59ef0c0f39bd79eb59030ab2Ecco Park * The event buffer has to be freed by the caller.
12199bfc35243bc810e59ef0c0f39bd79eb59030ab2Ecco Park */
12299bfc35243bc810e59ef0c0f39bd79eb59030ab2Ecco Park
12399bfc35243bc810e59ef0c0f39bd79eb59030ab2Ecco Parkstatic int send_hci_cmd_sync(int dev, uint8_t *cmd, int len, uint8_t **event)
12499bfc35243bc810e59ef0c0f39bd79eb59030ab2Ecco Park{
12599bfc35243bc810e59ef0c0f39bd79eb59030ab2Ecco Park    int err;
12699bfc35243bc810e59ef0c0f39bd79eb59030ab2Ecco Park    uint8_t *hci_event;
12799bfc35243bc810e59ef0c0f39bd79eb59030ab2Ecco Park    uint8_t pkt_type = HCI_COMMAND_PKT;
12899bfc35243bc810e59ef0c0f39bd79eb59030ab2Ecco Park
12999bfc35243bc810e59ef0c0f39bd79eb59030ab2Ecco Park    if (len == 0)
13099bfc35243bc810e59ef0c0f39bd79eb59030ab2Ecco Park    return len;
13199bfc35243bc810e59ef0c0f39bd79eb59030ab2Ecco Park
13299bfc35243bc810e59ef0c0f39bd79eb59030ab2Ecco Park    if (write(dev, &pkt_type, 1) != 1)
13399bfc35243bc810e59ef0c0f39bd79eb59030ab2Ecco Park        return -EILSEQ;
13499bfc35243bc810e59ef0c0f39bd79eb59030ab2Ecco Park    if (write(dev, (unsigned char *)cmd, len) != len)
13599bfc35243bc810e59ef0c0f39bd79eb59030ab2Ecco Park        return -EILSEQ;
13699bfc35243bc810e59ef0c0f39bd79eb59030ab2Ecco Park
13799bfc35243bc810e59ef0c0f39bd79eb59030ab2Ecco Park    hci_event = (uint8_t *)malloc(PS_EVENT_LEN);
13899bfc35243bc810e59ef0c0f39bd79eb59030ab2Ecco Park    if (!hci_event)
13999bfc35243bc810e59ef0c0f39bd79eb59030ab2Ecco Park        return -ENOMEM;
14099bfc35243bc810e59ef0c0f39bd79eb59030ab2Ecco Park
14199bfc35243bc810e59ef0c0f39bd79eb59030ab2Ecco Park    err = read_hci_event(dev, (unsigned char *)hci_event, PS_EVENT_LEN);
14299bfc35243bc810e59ef0c0f39bd79eb59030ab2Ecco Park    if (err > 0) {
14399bfc35243bc810e59ef0c0f39bd79eb59030ab2Ecco Park        *event = hci_event;
14499bfc35243bc810e59ef0c0f39bd79eb59030ab2Ecco Park    } else {
14599bfc35243bc810e59ef0c0f39bd79eb59030ab2Ecco Park        free(hci_event);
14699bfc35243bc810e59ef0c0f39bd79eb59030ab2Ecco Park        return -EILSEQ;
14799bfc35243bc810e59ef0c0f39bd79eb59030ab2Ecco Park    }
14899bfc35243bc810e59ef0c0f39bd79eb59030ab2Ecco Park
14999bfc35243bc810e59ef0c0f39bd79eb59030ab2Ecco Park    return len;
15099bfc35243bc810e59ef0c0f39bd79eb59030ab2Ecco Park}
15199bfc35243bc810e59ef0c0f39bd79eb59030ab2Ecco Park
15299bfc35243bc810e59ef0c0f39bd79eb59030ab2Ecco Parkstatic void convert_bdaddr(char *str_bdaddr, char *bdaddr)
15399bfc35243bc810e59ef0c0f39bd79eb59030ab2Ecco Park{
15499bfc35243bc810e59ef0c0f39bd79eb59030ab2Ecco Park    char bdbyte[3];
15599bfc35243bc810e59ef0c0f39bd79eb59030ab2Ecco Park    char *str_byte = str_bdaddr;
15699bfc35243bc810e59ef0c0f39bd79eb59030ab2Ecco Park    int i, j;
15799bfc35243bc810e59ef0c0f39bd79eb59030ab2Ecco Park    int colon_present = 0;
15899bfc35243bc810e59ef0c0f39bd79eb59030ab2Ecco Park
15999bfc35243bc810e59ef0c0f39bd79eb59030ab2Ecco Park    if (strstr(str_bdaddr, ":"))
16099bfc35243bc810e59ef0c0f39bd79eb59030ab2Ecco Park        colon_present = 1;
16199bfc35243bc810e59ef0c0f39bd79eb59030ab2Ecco Park
16299bfc35243bc810e59ef0c0f39bd79eb59030ab2Ecco Park    bdbyte[2] = '\0';
16399bfc35243bc810e59ef0c0f39bd79eb59030ab2Ecco Park
16499bfc35243bc810e59ef0c0f39bd79eb59030ab2Ecco Park    /* Reverse the BDADDR to LSB first */
16599bfc35243bc810e59ef0c0f39bd79eb59030ab2Ecco Park    for (i = 0, j = 5; i < 6; i++, j--) {
16699bfc35243bc810e59ef0c0f39bd79eb59030ab2Ecco Park        bdbyte[0] = str_byte[0];
16799bfc35243bc810e59ef0c0f39bd79eb59030ab2Ecco Park        bdbyte[1] = str_byte[1];
16899bfc35243bc810e59ef0c0f39bd79eb59030ab2Ecco Park        bdaddr[j] = strtol(bdbyte, NULL, 16);
16999bfc35243bc810e59ef0c0f39bd79eb59030ab2Ecco Park
17099bfc35243bc810e59ef0c0f39bd79eb59030ab2Ecco Park        if (colon_present == 1)
17199bfc35243bc810e59ef0c0f39bd79eb59030ab2Ecco Park            str_byte += 3;
17299bfc35243bc810e59ef0c0f39bd79eb59030ab2Ecco Park        else
17399bfc35243bc810e59ef0c0f39bd79eb59030ab2Ecco Park            str_byte += 2;
17499bfc35243bc810e59ef0c0f39bd79eb59030ab2Ecco Park    }
17599bfc35243bc810e59ef0c0f39bd79eb59030ab2Ecco Park}
17699bfc35243bc810e59ef0c0f39bd79eb59030ab2Ecco Park
17799bfc35243bc810e59ef0c0f39bd79eb59030ab2Ecco Parkstatic int uart_speed(int s)
17899bfc35243bc810e59ef0c0f39bd79eb59030ab2Ecco Park{
17999bfc35243bc810e59ef0c0f39bd79eb59030ab2Ecco Park    switch (s) {
18099bfc35243bc810e59ef0c0f39bd79eb59030ab2Ecco Park        case 9600:
18199bfc35243bc810e59ef0c0f39bd79eb59030ab2Ecco Park            return B9600;
18299bfc35243bc810e59ef0c0f39bd79eb59030ab2Ecco Park        case 19200:
18399bfc35243bc810e59ef0c0f39bd79eb59030ab2Ecco Park            return B19200;
18499bfc35243bc810e59ef0c0f39bd79eb59030ab2Ecco Park        case 38400:
18599bfc35243bc810e59ef0c0f39bd79eb59030ab2Ecco Park            return B38400;
18699bfc35243bc810e59ef0c0f39bd79eb59030ab2Ecco Park        case 57600:
18799bfc35243bc810e59ef0c0f39bd79eb59030ab2Ecco Park            return B57600;
18899bfc35243bc810e59ef0c0f39bd79eb59030ab2Ecco Park        case 115200:
18999bfc35243bc810e59ef0c0f39bd79eb59030ab2Ecco Park            return B115200;
19099bfc35243bc810e59ef0c0f39bd79eb59030ab2Ecco Park        case 230400:
19199bfc35243bc810e59ef0c0f39bd79eb59030ab2Ecco Park            return B230400;
19299bfc35243bc810e59ef0c0f39bd79eb59030ab2Ecco Park        case 460800:
19399bfc35243bc810e59ef0c0f39bd79eb59030ab2Ecco Park            return B460800;
19499bfc35243bc810e59ef0c0f39bd79eb59030ab2Ecco Park        case 500000:
19599bfc35243bc810e59ef0c0f39bd79eb59030ab2Ecco Park            return B500000;
19699bfc35243bc810e59ef0c0f39bd79eb59030ab2Ecco Park        case 576000:
19799bfc35243bc810e59ef0c0f39bd79eb59030ab2Ecco Park            return B576000;
19899bfc35243bc810e59ef0c0f39bd79eb59030ab2Ecco Park        case 921600:
19999bfc35243bc810e59ef0c0f39bd79eb59030ab2Ecco Park            return B921600;
20099bfc35243bc810e59ef0c0f39bd79eb59030ab2Ecco Park        case 1000000:
20199bfc35243bc810e59ef0c0f39bd79eb59030ab2Ecco Park            return B1000000;
20299bfc35243bc810e59ef0c0f39bd79eb59030ab2Ecco Park        case 1152000:
20399bfc35243bc810e59ef0c0f39bd79eb59030ab2Ecco Park            return B1152000;
20499bfc35243bc810e59ef0c0f39bd79eb59030ab2Ecco Park        case 1500000:
20599bfc35243bc810e59ef0c0f39bd79eb59030ab2Ecco Park            return B1500000;
20699bfc35243bc810e59ef0c0f39bd79eb59030ab2Ecco Park        case 2000000:
20799bfc35243bc810e59ef0c0f39bd79eb59030ab2Ecco Park            return B2000000;
20899bfc35243bc810e59ef0c0f39bd79eb59030ab2Ecco Park#ifdef B2500000
20999bfc35243bc810e59ef0c0f39bd79eb59030ab2Ecco Park        case 2500000:
21099bfc35243bc810e59ef0c0f39bd79eb59030ab2Ecco Park            return B2500000;
21199bfc35243bc810e59ef0c0f39bd79eb59030ab2Ecco Park#endif
21299bfc35243bc810e59ef0c0f39bd79eb59030ab2Ecco Park#ifdef B3000000
21399bfc35243bc810e59ef0c0f39bd79eb59030ab2Ecco Park        case 3000000:
21499bfc35243bc810e59ef0c0f39bd79eb59030ab2Ecco Park            return B3000000;
21599bfc35243bc810e59ef0c0f39bd79eb59030ab2Ecco Park#endif
21699bfc35243bc810e59ef0c0f39bd79eb59030ab2Ecco Park#ifdef B3500000
21799bfc35243bc810e59ef0c0f39bd79eb59030ab2Ecco Park        case 3500000:
21899bfc35243bc810e59ef0c0f39bd79eb59030ab2Ecco Park            return B3500000;
21999bfc35243bc810e59ef0c0f39bd79eb59030ab2Ecco Park#endif
22099bfc35243bc810e59ef0c0f39bd79eb59030ab2Ecco Park#ifdef B4000000
22199bfc35243bc810e59ef0c0f39bd79eb59030ab2Ecco Park        case 4000000:
22299bfc35243bc810e59ef0c0f39bd79eb59030ab2Ecco Park            return B4000000;
22399bfc35243bc810e59ef0c0f39bd79eb59030ab2Ecco Park#endif
22499bfc35243bc810e59ef0c0f39bd79eb59030ab2Ecco Park        default:
22599bfc35243bc810e59ef0c0f39bd79eb59030ab2Ecco Park            return B57600;
22699bfc35243bc810e59ef0c0f39bd79eb59030ab2Ecco Park    }
22799bfc35243bc810e59ef0c0f39bd79eb59030ab2Ecco Park}
22899bfc35243bc810e59ef0c0f39bd79eb59030ab2Ecco Park
22999bfc35243bc810e59ef0c0f39bd79eb59030ab2Ecco Parkint set_speed(int fd, struct termios *ti, int speed)
23099bfc35243bc810e59ef0c0f39bd79eb59030ab2Ecco Park{
23199bfc35243bc810e59ef0c0f39bd79eb59030ab2Ecco Park    if (cfsetospeed(ti, uart_speed(speed)) < 0)
23299bfc35243bc810e59ef0c0f39bd79eb59030ab2Ecco Park        return -errno;
23399bfc35243bc810e59ef0c0f39bd79eb59030ab2Ecco Park
23499bfc35243bc810e59ef0c0f39bd79eb59030ab2Ecco Park    if (cfsetispeed(ti, uart_speed(speed)) < 0)
23599bfc35243bc810e59ef0c0f39bd79eb59030ab2Ecco Park        return -errno;
23699bfc35243bc810e59ef0c0f39bd79eb59030ab2Ecco Park
23799bfc35243bc810e59ef0c0f39bd79eb59030ab2Ecco Park    if (tcsetattr(fd, TCSANOW, ti) < 0)
23899bfc35243bc810e59ef0c0f39bd79eb59030ab2Ecco Park        return -errno;
23999bfc35243bc810e59ef0c0f39bd79eb59030ab2Ecco Park
24099bfc35243bc810e59ef0c0f39bd79eb59030ab2Ecco Park    return 0;
24199bfc35243bc810e59ef0c0f39bd79eb59030ab2Ecco Park}
24299bfc35243bc810e59ef0c0f39bd79eb59030ab2Ecco Park
24399bfc35243bc810e59ef0c0f39bd79eb59030ab2Ecco Parkstatic void load_hci_ps_hdr(uint8_t *cmd, uint8_t ps_op, int len, int index)
24499bfc35243bc810e59ef0c0f39bd79eb59030ab2Ecco Park{
24599bfc35243bc810e59ef0c0f39bd79eb59030ab2Ecco Park    hci_command_hdr *ch = (void *)cmd;
24699bfc35243bc810e59ef0c0f39bd79eb59030ab2Ecco Park
24799bfc35243bc810e59ef0c0f39bd79eb59030ab2Ecco Park    ch->opcode = htobs(cmd_opcode_pack(HCI_VENDOR_CMD_OGF,
24899bfc35243bc810e59ef0c0f39bd79eb59030ab2Ecco Park        HCI_PS_CMD_OCF));
24999bfc35243bc810e59ef0c0f39bd79eb59030ab2Ecco Park    ch->plen = len + PS_HDR_LEN;
25099bfc35243bc810e59ef0c0f39bd79eb59030ab2Ecco Park    cmd += HCI_COMMAND_HDR_SIZE;
25199bfc35243bc810e59ef0c0f39bd79eb59030ab2Ecco Park
25299bfc35243bc810e59ef0c0f39bd79eb59030ab2Ecco Park    cmd[0] = ps_op;
25399bfc35243bc810e59ef0c0f39bd79eb59030ab2Ecco Park    cmd[1] = index;
25499bfc35243bc810e59ef0c0f39bd79eb59030ab2Ecco Park    cmd[2] = index >> 8;
25599bfc35243bc810e59ef0c0f39bd79eb59030ab2Ecco Park    cmd[3] = len;
25699bfc35243bc810e59ef0c0f39bd79eb59030ab2Ecco Park}
25799bfc35243bc810e59ef0c0f39bd79eb59030ab2Ecco Park
25899bfc35243bc810e59ef0c0f39bd79eb59030ab2Ecco Park
25999bfc35243bc810e59ef0c0f39bd79eb59030ab2Ecco Parkstatic int read_ps_event(uint8_t *event, uint16_t ocf)
26099bfc35243bc810e59ef0c0f39bd79eb59030ab2Ecco Park{
26199bfc35243bc810e59ef0c0f39bd79eb59030ab2Ecco Park    hci_event_hdr *eh;
26299bfc35243bc810e59ef0c0f39bd79eb59030ab2Ecco Park    uint16_t opcode = htobs(cmd_opcode_pack(HCI_VENDOR_CMD_OGF, ocf));
26399bfc35243bc810e59ef0c0f39bd79eb59030ab2Ecco Park
26499bfc35243bc810e59ef0c0f39bd79eb59030ab2Ecco Park    event++;
26599bfc35243bc810e59ef0c0f39bd79eb59030ab2Ecco Park
26699bfc35243bc810e59ef0c0f39bd79eb59030ab2Ecco Park    eh = (void *)event;
26799bfc35243bc810e59ef0c0f39bd79eb59030ab2Ecco Park    event += HCI_EVENT_HDR_SIZE;
26899bfc35243bc810e59ef0c0f39bd79eb59030ab2Ecco Park
26999bfc35243bc810e59ef0c0f39bd79eb59030ab2Ecco Park    if (eh->evt == EVT_CMD_COMPLETE) {
27099bfc35243bc810e59ef0c0f39bd79eb59030ab2Ecco Park        evt_cmd_complete *cc = (void *)event;
27199bfc35243bc810e59ef0c0f39bd79eb59030ab2Ecco Park
27299bfc35243bc810e59ef0c0f39bd79eb59030ab2Ecco Park        event += EVT_CMD_COMPLETE_SIZE;
27399bfc35243bc810e59ef0c0f39bd79eb59030ab2Ecco Park
27499bfc35243bc810e59ef0c0f39bd79eb59030ab2Ecco Park        if (cc->opcode == opcode && event[0] == HCI_EV_SUCCESS)
27599bfc35243bc810e59ef0c0f39bd79eb59030ab2Ecco Park            return 0;
27699bfc35243bc810e59ef0c0f39bd79eb59030ab2Ecco Park        else
27799bfc35243bc810e59ef0c0f39bd79eb59030ab2Ecco Park            return -EILSEQ;
27899bfc35243bc810e59ef0c0f39bd79eb59030ab2Ecco Park    }
27999bfc35243bc810e59ef0c0f39bd79eb59030ab2Ecco Park
28099bfc35243bc810e59ef0c0f39bd79eb59030ab2Ecco Park    return -EILSEQ;
28199bfc35243bc810e59ef0c0f39bd79eb59030ab2Ecco Park}
28299bfc35243bc810e59ef0c0f39bd79eb59030ab2Ecco Park
28399bfc35243bc810e59ef0c0f39bd79eb59030ab2Ecco Park#define PS_WRITE           1
28499bfc35243bc810e59ef0c0f39bd79eb59030ab2Ecco Park#define PS_RESET           2
28599bfc35243bc810e59ef0c0f39bd79eb59030ab2Ecco Park#define WRITE_PATCH        8
28699bfc35243bc810e59ef0c0f39bd79eb59030ab2Ecco Park#define ENABLE_PATCH       11
28799bfc35243bc810e59ef0c0f39bd79eb59030ab2Ecco Park
28899bfc35243bc810e59ef0c0f39bd79eb59030ab2Ecco Park#define HCI_PS_CMD_HDR_LEN 7
28999bfc35243bc810e59ef0c0f39bd79eb59030ab2Ecco Park
29099bfc35243bc810e59ef0c0f39bd79eb59030ab2Ecco Parkstatic int write_cmd(int fd, uint8_t *buffer, int len)
29199bfc35243bc810e59ef0c0f39bd79eb59030ab2Ecco Park{
29299bfc35243bc810e59ef0c0f39bd79eb59030ab2Ecco Park    uint8_t *event;
29399bfc35243bc810e59ef0c0f39bd79eb59030ab2Ecco Park    int err;
29499bfc35243bc810e59ef0c0f39bd79eb59030ab2Ecco Park
29599bfc35243bc810e59ef0c0f39bd79eb59030ab2Ecco Park    err = send_hci_cmd_sync(fd, buffer, len, &event);
29699bfc35243bc810e59ef0c0f39bd79eb59030ab2Ecco Park    if (err < 0)
29799bfc35243bc810e59ef0c0f39bd79eb59030ab2Ecco Park        return err;
29899bfc35243bc810e59ef0c0f39bd79eb59030ab2Ecco Park
29999bfc35243bc810e59ef0c0f39bd79eb59030ab2Ecco Park    err = read_ps_event(event, HCI_PS_CMD_OCF);
30099bfc35243bc810e59ef0c0f39bd79eb59030ab2Ecco Park
30199bfc35243bc810e59ef0c0f39bd79eb59030ab2Ecco Park    free(event);
30299bfc35243bc810e59ef0c0f39bd79eb59030ab2Ecco Park
30399bfc35243bc810e59ef0c0f39bd79eb59030ab2Ecco Park    return err;
30499bfc35243bc810e59ef0c0f39bd79eb59030ab2Ecco Park}
30599bfc35243bc810e59ef0c0f39bd79eb59030ab2Ecco Park
30699bfc35243bc810e59ef0c0f39bd79eb59030ab2Ecco Park#define PS_RESET_PARAM_LEN 6
30799bfc35243bc810e59ef0c0f39bd79eb59030ab2Ecco Park#define PS_RESET_CMD_LEN   (HCI_PS_CMD_HDR_LEN + PS_RESET_PARAM_LEN)
30899bfc35243bc810e59ef0c0f39bd79eb59030ab2Ecco Park
30999bfc35243bc810e59ef0c0f39bd79eb59030ab2Ecco Park#define PS_ID_MASK         0xFF
31099bfc35243bc810e59ef0c0f39bd79eb59030ab2Ecco Park
31199bfc35243bc810e59ef0c0f39bd79eb59030ab2Ecco Park/* Sends PS commands using vendor specficic HCI commands */
31299bfc35243bc810e59ef0c0f39bd79eb59030ab2Ecco Parkstatic int write_ps_cmd(int fd, uint8_t opcode, uint32_t ps_param)
31399bfc35243bc810e59ef0c0f39bd79eb59030ab2Ecco Park{
31499bfc35243bc810e59ef0c0f39bd79eb59030ab2Ecco Park    uint8_t cmd[HCI_MAX_CMD_SIZE];
31599bfc35243bc810e59ef0c0f39bd79eb59030ab2Ecco Park    uint32_t i;
31699bfc35243bc810e59ef0c0f39bd79eb59030ab2Ecco Park
31799bfc35243bc810e59ef0c0f39bd79eb59030ab2Ecco Park    switch (opcode) {
31899bfc35243bc810e59ef0c0f39bd79eb59030ab2Ecco Park        case ENABLE_PATCH:
31999bfc35243bc810e59ef0c0f39bd79eb59030ab2Ecco Park            load_hci_ps_hdr(cmd, opcode, 0, 0x00);
32099bfc35243bc810e59ef0c0f39bd79eb59030ab2Ecco Park
32199bfc35243bc810e59ef0c0f39bd79eb59030ab2Ecco Park            if (write_cmd(fd, cmd, HCI_PS_CMD_HDR_LEN) < 0)
32299bfc35243bc810e59ef0c0f39bd79eb59030ab2Ecco Park                return -EILSEQ;
32399bfc35243bc810e59ef0c0f39bd79eb59030ab2Ecco Park            break;
32499bfc35243bc810e59ef0c0f39bd79eb59030ab2Ecco Park
32599bfc35243bc810e59ef0c0f39bd79eb59030ab2Ecco Park        case PS_RESET:
32699bfc35243bc810e59ef0c0f39bd79eb59030ab2Ecco Park            load_hci_ps_hdr(cmd, opcode, PS_RESET_PARAM_LEN, 0x00);
32799bfc35243bc810e59ef0c0f39bd79eb59030ab2Ecco Park
32899bfc35243bc810e59ef0c0f39bd79eb59030ab2Ecco Park            cmd[7] = 0x00;
32999bfc35243bc810e59ef0c0f39bd79eb59030ab2Ecco Park            cmd[PS_RESET_CMD_LEN - 2] = ps_param & PS_ID_MASK;
33099bfc35243bc810e59ef0c0f39bd79eb59030ab2Ecco Park            cmd[PS_RESET_CMD_LEN - 1] = (ps_param >> 8) & PS_ID_MASK;
33199bfc35243bc810e59ef0c0f39bd79eb59030ab2Ecco Park
33299bfc35243bc810e59ef0c0f39bd79eb59030ab2Ecco Park            if (write_cmd(fd, cmd, PS_RESET_CMD_LEN) < 0)
33399bfc35243bc810e59ef0c0f39bd79eb59030ab2Ecco Park                return -EILSEQ;
33499bfc35243bc810e59ef0c0f39bd79eb59030ab2Ecco Park            break;
33599bfc35243bc810e59ef0c0f39bd79eb59030ab2Ecco Park
33699bfc35243bc810e59ef0c0f39bd79eb59030ab2Ecco Park        case PS_WRITE:
33799bfc35243bc810e59ef0c0f39bd79eb59030ab2Ecco Park            for (i = 0; i < ps_param; i++) {
33899bfc35243bc810e59ef0c0f39bd79eb59030ab2Ecco Park                load_hci_ps_hdr(cmd, opcode, ps_list[i].len,
33999bfc35243bc810e59ef0c0f39bd79eb59030ab2Ecco Park                ps_list[i].id);
34099bfc35243bc810e59ef0c0f39bd79eb59030ab2Ecco Park
34199bfc35243bc810e59ef0c0f39bd79eb59030ab2Ecco Park                memcpy(&cmd[HCI_PS_CMD_HDR_LEN], ps_list[i].data,
34299bfc35243bc810e59ef0c0f39bd79eb59030ab2Ecco Park                ps_list[i].len);
34399bfc35243bc810e59ef0c0f39bd79eb59030ab2Ecco Park
34499bfc35243bc810e59ef0c0f39bd79eb59030ab2Ecco Park                if (write_cmd(fd, cmd, ps_list[i].len +
34599bfc35243bc810e59ef0c0f39bd79eb59030ab2Ecco Park                    HCI_PS_CMD_HDR_LEN) < 0)
34699bfc35243bc810e59ef0c0f39bd79eb59030ab2Ecco Park                    return -EILSEQ;
34799bfc35243bc810e59ef0c0f39bd79eb59030ab2Ecco Park            }
34899bfc35243bc810e59ef0c0f39bd79eb59030ab2Ecco Park            break;
34999bfc35243bc810e59ef0c0f39bd79eb59030ab2Ecco Park    }
35099bfc35243bc810e59ef0c0f39bd79eb59030ab2Ecco Park
35199bfc35243bc810e59ef0c0f39bd79eb59030ab2Ecco Park    return 0;
35299bfc35243bc810e59ef0c0f39bd79eb59030ab2Ecco Park}
35399bfc35243bc810e59ef0c0f39bd79eb59030ab2Ecco Park
35499bfc35243bc810e59ef0c0f39bd79eb59030ab2Ecco Park#define PS_ASIC_FILE    "PS_ASIC.pst"
35599bfc35243bc810e59ef0c0f39bd79eb59030ab2Ecco Park#define PS_FPGA_FILE    "PS_FPGA.pst"
35699bfc35243bc810e59ef0c0f39bd79eb59030ab2Ecco Park#define MAXPATHLEN  4096
35799bfc35243bc810e59ef0c0f39bd79eb59030ab2Ecco Parkstatic void get_ps_file_name(uint32_t devtype, uint32_t rom_version,char *path)
35899bfc35243bc810e59ef0c0f39bd79eb59030ab2Ecco Park{
35999bfc35243bc810e59ef0c0f39bd79eb59030ab2Ecco Park    char *filename;
36099bfc35243bc810e59ef0c0f39bd79eb59030ab2Ecco Park
36199bfc35243bc810e59ef0c0f39bd79eb59030ab2Ecco Park    if (devtype == 0xdeadc0de)
36299bfc35243bc810e59ef0c0f39bd79eb59030ab2Ecco Park        filename = PS_ASIC_FILE;
36399bfc35243bc810e59ef0c0f39bd79eb59030ab2Ecco Park    else
36499bfc35243bc810e59ef0c0f39bd79eb59030ab2Ecco Park        filename = PS_FPGA_FILE;
36599bfc35243bc810e59ef0c0f39bd79eb59030ab2Ecco Park
36699bfc35243bc810e59ef0c0f39bd79eb59030ab2Ecco Park    snprintf(path, MAXPATHLEN, "%s%x/%s", FW_PATH, rom_version, filename);
36799bfc35243bc810e59ef0c0f39bd79eb59030ab2Ecco Park}
36899bfc35243bc810e59ef0c0f39bd79eb59030ab2Ecco Park
36999bfc35243bc810e59ef0c0f39bd79eb59030ab2Ecco Park#define PATCH_FILE        "RamPatch.txt"
37099bfc35243bc810e59ef0c0f39bd79eb59030ab2Ecco Park#define FPGA_ROM_VERSION  0x99999999
37199bfc35243bc810e59ef0c0f39bd79eb59030ab2Ecco Park#define ROM_DEV_TYPE      0xdeadc0de
37299bfc35243bc810e59ef0c0f39bd79eb59030ab2Ecco Park
37399bfc35243bc810e59ef0c0f39bd79eb59030ab2Ecco Parkstatic void get_patch_file_name(uint32_t dev_type, uint32_t rom_version,
37499bfc35243bc810e59ef0c0f39bd79eb59030ab2Ecco Park    uint32_t build_version, char *path)
37599bfc35243bc810e59ef0c0f39bd79eb59030ab2Ecco Park{
37699bfc35243bc810e59ef0c0f39bd79eb59030ab2Ecco Park    if (rom_version == FPGA_ROM_VERSION && dev_type != ROM_DEV_TYPE
37799bfc35243bc810e59ef0c0f39bd79eb59030ab2Ecco Park            &&dev_type != 0 && build_version == 1)
37899bfc35243bc810e59ef0c0f39bd79eb59030ab2Ecco Park        path[0] = '\0';
37999bfc35243bc810e59ef0c0f39bd79eb59030ab2Ecco Park    else
38099bfc35243bc810e59ef0c0f39bd79eb59030ab2Ecco Park        snprintf(path, MAXPATHLEN, "%s%x/%s", FW_PATH, rom_version, PATCH_FILE);
38199bfc35243bc810e59ef0c0f39bd79eb59030ab2Ecco Park}
38299bfc35243bc810e59ef0c0f39bd79eb59030ab2Ecco Park
38399bfc35243bc810e59ef0c0f39bd79eb59030ab2Ecco Parkstatic int set_cntrlr_baud(int fd, int speed)
38499bfc35243bc810e59ef0c0f39bd79eb59030ab2Ecco Park{
38599bfc35243bc810e59ef0c0f39bd79eb59030ab2Ecco Park    int baud;
38699bfc35243bc810e59ef0c0f39bd79eb59030ab2Ecco Park    struct timespec tm = { 0, 500000};
38799bfc35243bc810e59ef0c0f39bd79eb59030ab2Ecco Park    unsigned char cmd[MAX_CMD_LEN], rsp[HCI_MAX_EVENT_SIZE];
38899bfc35243bc810e59ef0c0f39bd79eb59030ab2Ecco Park    unsigned char *ptr = cmd + 1;
38999bfc35243bc810e59ef0c0f39bd79eb59030ab2Ecco Park    hci_command_hdr *ch = (void *)ptr;
39099bfc35243bc810e59ef0c0f39bd79eb59030ab2Ecco Park
39199bfc35243bc810e59ef0c0f39bd79eb59030ab2Ecco Park    cmd[0] = HCI_COMMAND_PKT;
39299bfc35243bc810e59ef0c0f39bd79eb59030ab2Ecco Park
39399bfc35243bc810e59ef0c0f39bd79eb59030ab2Ecco Park    /* set controller baud rate to user specified value */
39499bfc35243bc810e59ef0c0f39bd79eb59030ab2Ecco Park    ptr = cmd + 1;
39599bfc35243bc810e59ef0c0f39bd79eb59030ab2Ecco Park    ch->opcode = htobs(cmd_opcode_pack(HCI_VENDOR_CMD_OGF,
39699bfc35243bc810e59ef0c0f39bd79eb59030ab2Ecco Park    HCI_CHG_BAUD_CMD_OCF));
39799bfc35243bc810e59ef0c0f39bd79eb59030ab2Ecco Park    ch->plen = 2;
39899bfc35243bc810e59ef0c0f39bd79eb59030ab2Ecco Park    ptr += HCI_COMMAND_HDR_SIZE;
39999bfc35243bc810e59ef0c0f39bd79eb59030ab2Ecco Park
40099bfc35243bc810e59ef0c0f39bd79eb59030ab2Ecco Park    baud = speed/100;
40199bfc35243bc810e59ef0c0f39bd79eb59030ab2Ecco Park    ptr[0] = (char)baud;
40299bfc35243bc810e59ef0c0f39bd79eb59030ab2Ecco Park    ptr[1] = (char)(baud >> 8);
40399bfc35243bc810e59ef0c0f39bd79eb59030ab2Ecco Park
40499bfc35243bc810e59ef0c0f39bd79eb59030ab2Ecco Park    if (write(fd, cmd, WRITE_BAUD_CMD_LEN) != WRITE_BAUD_CMD_LEN) {
40599bfc35243bc810e59ef0c0f39bd79eb59030ab2Ecco Park        ALOGI("Failed to write change baud rate command");
40699bfc35243bc810e59ef0c0f39bd79eb59030ab2Ecco Park        return -ETIMEDOUT;
40799bfc35243bc810e59ef0c0f39bd79eb59030ab2Ecco Park    }
40899bfc35243bc810e59ef0c0f39bd79eb59030ab2Ecco Park
40999bfc35243bc810e59ef0c0f39bd79eb59030ab2Ecco Park    nanosleep(&tm, NULL);
41099bfc35243bc810e59ef0c0f39bd79eb59030ab2Ecco Park
41199bfc35243bc810e59ef0c0f39bd79eb59030ab2Ecco Park    if (read_hci_event(fd, rsp, sizeof(rsp)) < 0)
41299bfc35243bc810e59ef0c0f39bd79eb59030ab2Ecco Park        return -ETIMEDOUT;
41399bfc35243bc810e59ef0c0f39bd79eb59030ab2Ecco Park
41499bfc35243bc810e59ef0c0f39bd79eb59030ab2Ecco Park    return 0;
41599bfc35243bc810e59ef0c0f39bd79eb59030ab2Ecco Park}
41699bfc35243bc810e59ef0c0f39bd79eb59030ab2Ecco Park
41799bfc35243bc810e59ef0c0f39bd79eb59030ab2Ecco Park#define PS_UNDEF   0
41899bfc35243bc810e59ef0c0f39bd79eb59030ab2Ecco Park#define PS_ID      1
41999bfc35243bc810e59ef0c0f39bd79eb59030ab2Ecco Park#define PS_LEN     2
42099bfc35243bc810e59ef0c0f39bd79eb59030ab2Ecco Park#define PS_DATA    3
42199bfc35243bc810e59ef0c0f39bd79eb59030ab2Ecco Park
42299bfc35243bc810e59ef0c0f39bd79eb59030ab2Ecco Park#define PS_MAX_LEN         500
42399bfc35243bc810e59ef0c0f39bd79eb59030ab2Ecco Park#define LINE_SIZE_MAX      (PS_MAX_LEN * 2)
42499bfc35243bc810e59ef0c0f39bd79eb59030ab2Ecco Park#define ENTRY_PER_LINE     16
42599bfc35243bc810e59ef0c0f39bd79eb59030ab2Ecco Park
42699bfc35243bc810e59ef0c0f39bd79eb59030ab2Ecco Park#define __check_comment(buf) (((buf)[0] == '/') && ((buf)[1] == '/'))
42799bfc35243bc810e59ef0c0f39bd79eb59030ab2Ecco Park#define __skip_space(str)      while (*(str) == ' ') ((str)++)
42899bfc35243bc810e59ef0c0f39bd79eb59030ab2Ecco Park
42999bfc35243bc810e59ef0c0f39bd79eb59030ab2Ecco Park
43099bfc35243bc810e59ef0c0f39bd79eb59030ab2Ecco Park#define __is_delim(ch) ((ch) == ':')
43199bfc35243bc810e59ef0c0f39bd79eb59030ab2Ecco Park#define MAX_PREAMBLE_LEN 4
43299bfc35243bc810e59ef0c0f39bd79eb59030ab2Ecco Park
43399bfc35243bc810e59ef0c0f39bd79eb59030ab2Ecco Park/* Parse PS entry preamble of format [X:X] for main type and subtype */
43499bfc35243bc810e59ef0c0f39bd79eb59030ab2Ecco Parkstatic int get_ps_type(char *ptr, int index, char *type, char *sub_type)
43599bfc35243bc810e59ef0c0f39bd79eb59030ab2Ecco Park{
43699bfc35243bc810e59ef0c0f39bd79eb59030ab2Ecco Park    int i;
43799bfc35243bc810e59ef0c0f39bd79eb59030ab2Ecco Park    int delim = FALSE;
43899bfc35243bc810e59ef0c0f39bd79eb59030ab2Ecco Park
43999bfc35243bc810e59ef0c0f39bd79eb59030ab2Ecco Park    if (index > MAX_PREAMBLE_LEN)
44099bfc35243bc810e59ef0c0f39bd79eb59030ab2Ecco Park        return -EILSEQ;
44199bfc35243bc810e59ef0c0f39bd79eb59030ab2Ecco Park
44299bfc35243bc810e59ef0c0f39bd79eb59030ab2Ecco Park    for (i = 1; i < index; i++) {
44399bfc35243bc810e59ef0c0f39bd79eb59030ab2Ecco Park        if (__is_delim(ptr[i])) {
44499bfc35243bc810e59ef0c0f39bd79eb59030ab2Ecco Park            delim = TRUE;
44599bfc35243bc810e59ef0c0f39bd79eb59030ab2Ecco Park            continue;
44699bfc35243bc810e59ef0c0f39bd79eb59030ab2Ecco Park        }
44799bfc35243bc810e59ef0c0f39bd79eb59030ab2Ecco Park
44899bfc35243bc810e59ef0c0f39bd79eb59030ab2Ecco Park        if (isalpha(ptr[i])) {
44999bfc35243bc810e59ef0c0f39bd79eb59030ab2Ecco Park            if (delim == FALSE)
45099bfc35243bc810e59ef0c0f39bd79eb59030ab2Ecco Park                (*type) = toupper(ptr[i]);
45199bfc35243bc810e59ef0c0f39bd79eb59030ab2Ecco Park            else
45299bfc35243bc810e59ef0c0f39bd79eb59030ab2Ecco Park                (*sub_type)	= toupper(ptr[i]);
45399bfc35243bc810e59ef0c0f39bd79eb59030ab2Ecco Park        }
45499bfc35243bc810e59ef0c0f39bd79eb59030ab2Ecco Park    }
45599bfc35243bc810e59ef0c0f39bd79eb59030ab2Ecco Park
45699bfc35243bc810e59ef0c0f39bd79eb59030ab2Ecco Park    return 0;
45799bfc35243bc810e59ef0c0f39bd79eb59030ab2Ecco Park}
45899bfc35243bc810e59ef0c0f39bd79eb59030ab2Ecco Park
45999bfc35243bc810e59ef0c0f39bd79eb59030ab2Ecco Park#define ARRAY   'A'
46099bfc35243bc810e59ef0c0f39bd79eb59030ab2Ecco Park#define STRING  'S'
46199bfc35243bc810e59ef0c0f39bd79eb59030ab2Ecco Park#define DECIMAL 'D'
46299bfc35243bc810e59ef0c0f39bd79eb59030ab2Ecco Park#define BINARY  'B'
46399bfc35243bc810e59ef0c0f39bd79eb59030ab2Ecco Park
46499bfc35243bc810e59ef0c0f39bd79eb59030ab2Ecco Park#define PS_HEX           0
46599bfc35243bc810e59ef0c0f39bd79eb59030ab2Ecco Park#define PS_DEC           1
46699bfc35243bc810e59ef0c0f39bd79eb59030ab2Ecco Park
46799bfc35243bc810e59ef0c0f39bd79eb59030ab2Ecco Parkstatic int get_input_format(char *buf, struct ps_entry_type *format)
46899bfc35243bc810e59ef0c0f39bd79eb59030ab2Ecco Park{
46999bfc35243bc810e59ef0c0f39bd79eb59030ab2Ecco Park    char *ptr = NULL;
47099bfc35243bc810e59ef0c0f39bd79eb59030ab2Ecco Park    char type = '\0';
47199bfc35243bc810e59ef0c0f39bd79eb59030ab2Ecco Park    char sub_type = '\0';
47299bfc35243bc810e59ef0c0f39bd79eb59030ab2Ecco Park
47399bfc35243bc810e59ef0c0f39bd79eb59030ab2Ecco Park    format->type = PS_HEX;
47499bfc35243bc810e59ef0c0f39bd79eb59030ab2Ecco Park    format->array = TRUE;
47599bfc35243bc810e59ef0c0f39bd79eb59030ab2Ecco Park
47699bfc35243bc810e59ef0c0f39bd79eb59030ab2Ecco Park    if (strstr(buf, "[") != buf)
47799bfc35243bc810e59ef0c0f39bd79eb59030ab2Ecco Park        return 0;
47899bfc35243bc810e59ef0c0f39bd79eb59030ab2Ecco Park
47999bfc35243bc810e59ef0c0f39bd79eb59030ab2Ecco Park    ptr = strstr(buf, "]");
48099bfc35243bc810e59ef0c0f39bd79eb59030ab2Ecco Park    if (!ptr)
48199bfc35243bc810e59ef0c0f39bd79eb59030ab2Ecco Park        return -EILSEQ;
48299bfc35243bc810e59ef0c0f39bd79eb59030ab2Ecco Park
48399bfc35243bc810e59ef0c0f39bd79eb59030ab2Ecco Park    if (get_ps_type(buf, ptr - buf, &type, &sub_type) < 0)
48499bfc35243bc810e59ef0c0f39bd79eb59030ab2Ecco Park        return -EILSEQ;
48599bfc35243bc810e59ef0c0f39bd79eb59030ab2Ecco Park
48699bfc35243bc810e59ef0c0f39bd79eb59030ab2Ecco Park    /* Check is data type is of array */
48799bfc35243bc810e59ef0c0f39bd79eb59030ab2Ecco Park    if (type == ARRAY || sub_type == ARRAY)
48899bfc35243bc810e59ef0c0f39bd79eb59030ab2Ecco Park        format->array = TRUE;
48999bfc35243bc810e59ef0c0f39bd79eb59030ab2Ecco Park
49099bfc35243bc810e59ef0c0f39bd79eb59030ab2Ecco Park    if (type == STRING || sub_type == STRING)
49199bfc35243bc810e59ef0c0f39bd79eb59030ab2Ecco Park        format->array = FALSE;
49299bfc35243bc810e59ef0c0f39bd79eb59030ab2Ecco Park
49399bfc35243bc810e59ef0c0f39bd79eb59030ab2Ecco Park    if (type == DECIMAL || type == BINARY)
49499bfc35243bc810e59ef0c0f39bd79eb59030ab2Ecco Park        format->type = PS_DEC;
49599bfc35243bc810e59ef0c0f39bd79eb59030ab2Ecco Park    else
49699bfc35243bc810e59ef0c0f39bd79eb59030ab2Ecco Park        format->type = PS_HEX;
49799bfc35243bc810e59ef0c0f39bd79eb59030ab2Ecco Park
49899bfc35243bc810e59ef0c0f39bd79eb59030ab2Ecco Park    return 0;
49999bfc35243bc810e59ef0c0f39bd79eb59030ab2Ecco Park}
50099bfc35243bc810e59ef0c0f39bd79eb59030ab2Ecco Park
50199bfc35243bc810e59ef0c0f39bd79eb59030ab2Ecco Park
50299bfc35243bc810e59ef0c0f39bd79eb59030ab2Ecco Park
50399bfc35243bc810e59ef0c0f39bd79eb59030ab2Ecco Park#define UNDEFINED 0xFFFF
50499bfc35243bc810e59ef0c0f39bd79eb59030ab2Ecco Park
50599bfc35243bc810e59ef0c0f39bd79eb59030ab2Ecco Parkstatic unsigned int read_data_in_section(char *buf, struct ps_entry_type type)
50699bfc35243bc810e59ef0c0f39bd79eb59030ab2Ecco Park{
50799bfc35243bc810e59ef0c0f39bd79eb59030ab2Ecco Park    char *ptr = buf;
50899bfc35243bc810e59ef0c0f39bd79eb59030ab2Ecco Park
50999bfc35243bc810e59ef0c0f39bd79eb59030ab2Ecco Park    if (!buf)
51099bfc35243bc810e59ef0c0f39bd79eb59030ab2Ecco Park        return UNDEFINED;
51199bfc35243bc810e59ef0c0f39bd79eb59030ab2Ecco Park
51299bfc35243bc810e59ef0c0f39bd79eb59030ab2Ecco Park    if (buf == strstr(buf, "[")) {
51399bfc35243bc810e59ef0c0f39bd79eb59030ab2Ecco Park        ptr = strstr(buf, "]");
51499bfc35243bc810e59ef0c0f39bd79eb59030ab2Ecco Park        if (!ptr)
51599bfc35243bc810e59ef0c0f39bd79eb59030ab2Ecco Park            return UNDEFINED;
51699bfc35243bc810e59ef0c0f39bd79eb59030ab2Ecco Park
51799bfc35243bc810e59ef0c0f39bd79eb59030ab2Ecco Park        ptr++;
51899bfc35243bc810e59ef0c0f39bd79eb59030ab2Ecco Park    }
51999bfc35243bc810e59ef0c0f39bd79eb59030ab2Ecco Park
52099bfc35243bc810e59ef0c0f39bd79eb59030ab2Ecco Park    if (type.type == PS_HEX && type.array != TRUE)
52199bfc35243bc810e59ef0c0f39bd79eb59030ab2Ecco Park        return strtol(ptr, NULL, 16);
52299bfc35243bc810e59ef0c0f39bd79eb59030ab2Ecco Park
52399bfc35243bc810e59ef0c0f39bd79eb59030ab2Ecco Park    return UNDEFINED;
52499bfc35243bc810e59ef0c0f39bd79eb59030ab2Ecco Park}
52599bfc35243bc810e59ef0c0f39bd79eb59030ab2Ecco Park
52699bfc35243bc810e59ef0c0f39bd79eb59030ab2Ecco Park
52799bfc35243bc810e59ef0c0f39bd79eb59030ab2Ecco Park/* Read PS entries as string, convert and add to Hex array */
52899bfc35243bc810e59ef0c0f39bd79eb59030ab2Ecco Parkstatic void update_tag_data(struct ps_cfg_entry *tag,
52999bfc35243bc810e59ef0c0f39bd79eb59030ab2Ecco Park    struct tag_info *info, const char *ptr)
53099bfc35243bc810e59ef0c0f39bd79eb59030ab2Ecco Park{
53199bfc35243bc810e59ef0c0f39bd79eb59030ab2Ecco Park    char buf[3];
53299bfc35243bc810e59ef0c0f39bd79eb59030ab2Ecco Park
53399bfc35243bc810e59ef0c0f39bd79eb59030ab2Ecco Park    buf[2] = '\0';
53499bfc35243bc810e59ef0c0f39bd79eb59030ab2Ecco Park
53599bfc35243bc810e59ef0c0f39bd79eb59030ab2Ecco Park    strlcpy(buf, &ptr[info->char_cnt],sizeof(buf));
53699bfc35243bc810e59ef0c0f39bd79eb59030ab2Ecco Park    tag->data[info->byte_count] = strtol(buf, NULL, 16);
53799bfc35243bc810e59ef0c0f39bd79eb59030ab2Ecco Park    info->char_cnt += 3;
53899bfc35243bc810e59ef0c0f39bd79eb59030ab2Ecco Park    info->byte_count++;
53999bfc35243bc810e59ef0c0f39bd79eb59030ab2Ecco Park
54099bfc35243bc810e59ef0c0f39bd79eb59030ab2Ecco Park    strlcpy(buf, &ptr[info->char_cnt], sizeof(buf));
54199bfc35243bc810e59ef0c0f39bd79eb59030ab2Ecco Park    tag->data[info->byte_count] = strtol(buf, NULL, 16);
54299bfc35243bc810e59ef0c0f39bd79eb59030ab2Ecco Park    info->char_cnt += 3;
54399bfc35243bc810e59ef0c0f39bd79eb59030ab2Ecco Park    info->byte_count++;
54499bfc35243bc810e59ef0c0f39bd79eb59030ab2Ecco Park}
54599bfc35243bc810e59ef0c0f39bd79eb59030ab2Ecco Park
54699bfc35243bc810e59ef0c0f39bd79eb59030ab2Ecco Parkstatic inline int update_char_count(const char *buf)
54799bfc35243bc810e59ef0c0f39bd79eb59030ab2Ecco Park{
54899bfc35243bc810e59ef0c0f39bd79eb59030ab2Ecco Park    char *end_ptr;
54999bfc35243bc810e59ef0c0f39bd79eb59030ab2Ecco Park
55099bfc35243bc810e59ef0c0f39bd79eb59030ab2Ecco Park    if (strstr(buf, "[") == buf) {
55199bfc35243bc810e59ef0c0f39bd79eb59030ab2Ecco Park        end_ptr = strstr(buf, "]");
55299bfc35243bc810e59ef0c0f39bd79eb59030ab2Ecco Park        if (!end_ptr)
55399bfc35243bc810e59ef0c0f39bd79eb59030ab2Ecco Park            return 0;
55499bfc35243bc810e59ef0c0f39bd79eb59030ab2Ecco Park        else
55599bfc35243bc810e59ef0c0f39bd79eb59030ab2Ecco Park            return(end_ptr - buf) +	1;
55699bfc35243bc810e59ef0c0f39bd79eb59030ab2Ecco Park    }
55799bfc35243bc810e59ef0c0f39bd79eb59030ab2Ecco Park
55899bfc35243bc810e59ef0c0f39bd79eb59030ab2Ecco Park    return 0;
55999bfc35243bc810e59ef0c0f39bd79eb59030ab2Ecco Park}
56099bfc35243bc810e59ef0c0f39bd79eb59030ab2Ecco Park
56199bfc35243bc810e59ef0c0f39bd79eb59030ab2Ecco Park#define PS_HEX           0
56299bfc35243bc810e59ef0c0f39bd79eb59030ab2Ecco Park#define PS_DEC           1
56399bfc35243bc810e59ef0c0f39bd79eb59030ab2Ecco Park
56499bfc35243bc810e59ef0c0f39bd79eb59030ab2Ecco Parkstatic int ath_parse_ps(FILE *stream)
56599bfc35243bc810e59ef0c0f39bd79eb59030ab2Ecco Park{
56699bfc35243bc810e59ef0c0f39bd79eb59030ab2Ecco Park    char buf[LINE_SIZE_MAX + 1];
56799bfc35243bc810e59ef0c0f39bd79eb59030ab2Ecco Park    char *ptr;
56899bfc35243bc810e59ef0c0f39bd79eb59030ab2Ecco Park    uint8_t tag_cnt = 0;
56999bfc35243bc810e59ef0c0f39bd79eb59030ab2Ecco Park    int16_t byte_count = 0;
57099bfc35243bc810e59ef0c0f39bd79eb59030ab2Ecco Park    struct ps_entry_type format;
57199bfc35243bc810e59ef0c0f39bd79eb59030ab2Ecco Park    struct tag_info status = { 0, 0, 0, 0};
57299bfc35243bc810e59ef0c0f39bd79eb59030ab2Ecco Park
57399bfc35243bc810e59ef0c0f39bd79eb59030ab2Ecco Park    do {
57499bfc35243bc810e59ef0c0f39bd79eb59030ab2Ecco Park        int read_count;
57599bfc35243bc810e59ef0c0f39bd79eb59030ab2Ecco Park        struct ps_cfg_entry *tag;
57699bfc35243bc810e59ef0c0f39bd79eb59030ab2Ecco Park
57799bfc35243bc810e59ef0c0f39bd79eb59030ab2Ecco Park        ptr = fgets(buf, LINE_SIZE_MAX, stream);
57899bfc35243bc810e59ef0c0f39bd79eb59030ab2Ecco Park        if (!ptr)
57999bfc35243bc810e59ef0c0f39bd79eb59030ab2Ecco Park            break;
58099bfc35243bc810e59ef0c0f39bd79eb59030ab2Ecco Park
58199bfc35243bc810e59ef0c0f39bd79eb59030ab2Ecco Park        __skip_space(ptr);
58299bfc35243bc810e59ef0c0f39bd79eb59030ab2Ecco Park        if (__check_comment(ptr))
58399bfc35243bc810e59ef0c0f39bd79eb59030ab2Ecco Park            continue;
58499bfc35243bc810e59ef0c0f39bd79eb59030ab2Ecco Park
58599bfc35243bc810e59ef0c0f39bd79eb59030ab2Ecco Park        /* Lines with a '#' will be followed by new PS entry */
58699bfc35243bc810e59ef0c0f39bd79eb59030ab2Ecco Park        if (ptr == strstr(ptr, "#")) {
58799bfc35243bc810e59ef0c0f39bd79eb59030ab2Ecco Park            if (status.section != PS_UNDEF) {
58899bfc35243bc810e59ef0c0f39bd79eb59030ab2Ecco Park                return -EILSEQ;
58999bfc35243bc810e59ef0c0f39bd79eb59030ab2Ecco Park            } else {
59099bfc35243bc810e59ef0c0f39bd79eb59030ab2Ecco Park                status.section = PS_ID;
59199bfc35243bc810e59ef0c0f39bd79eb59030ab2Ecco Park                continue;
59299bfc35243bc810e59ef0c0f39bd79eb59030ab2Ecco Park            }
59399bfc35243bc810e59ef0c0f39bd79eb59030ab2Ecco Park        }
59499bfc35243bc810e59ef0c0f39bd79eb59030ab2Ecco Park
59599bfc35243bc810e59ef0c0f39bd79eb59030ab2Ecco Park        tag = &ps_list[tag_cnt];
59699bfc35243bc810e59ef0c0f39bd79eb59030ab2Ecco Park
59799bfc35243bc810e59ef0c0f39bd79eb59030ab2Ecco Park        switch (status.section) {
59899bfc35243bc810e59ef0c0f39bd79eb59030ab2Ecco Park            case PS_ID:
59999bfc35243bc810e59ef0c0f39bd79eb59030ab2Ecco Park                if (get_input_format(ptr, &format) < 0)
60099bfc35243bc810e59ef0c0f39bd79eb59030ab2Ecco Park                    return -EILSEQ;
60199bfc35243bc810e59ef0c0f39bd79eb59030ab2Ecco Park
60299bfc35243bc810e59ef0c0f39bd79eb59030ab2Ecco Park                tag->id = read_data_in_section(ptr, format);
60399bfc35243bc810e59ef0c0f39bd79eb59030ab2Ecco Park                status.section = PS_LEN;
60499bfc35243bc810e59ef0c0f39bd79eb59030ab2Ecco Park                break;
60599bfc35243bc810e59ef0c0f39bd79eb59030ab2Ecco Park
60699bfc35243bc810e59ef0c0f39bd79eb59030ab2Ecco Park            case PS_LEN:
60799bfc35243bc810e59ef0c0f39bd79eb59030ab2Ecco Park                if (get_input_format(ptr, &format) < 0)
60899bfc35243bc810e59ef0c0f39bd79eb59030ab2Ecco Park                    return -EILSEQ;
60999bfc35243bc810e59ef0c0f39bd79eb59030ab2Ecco Park
61099bfc35243bc810e59ef0c0f39bd79eb59030ab2Ecco Park                byte_count = read_data_in_section(ptr, format);
61199bfc35243bc810e59ef0c0f39bd79eb59030ab2Ecco Park                if (byte_count > PS_MAX_LEN)
61299bfc35243bc810e59ef0c0f39bd79eb59030ab2Ecco Park                    return -EILSEQ;
61399bfc35243bc810e59ef0c0f39bd79eb59030ab2Ecco Park
61499bfc35243bc810e59ef0c0f39bd79eb59030ab2Ecco Park                tag->len = byte_count;
61599bfc35243bc810e59ef0c0f39bd79eb59030ab2Ecco Park                tag->data = (uint8_t *)malloc(byte_count);
61699bfc35243bc810e59ef0c0f39bd79eb59030ab2Ecco Park
61799bfc35243bc810e59ef0c0f39bd79eb59030ab2Ecco Park                status.section = PS_DATA;
61899bfc35243bc810e59ef0c0f39bd79eb59030ab2Ecco Park                status.line_count = 0;
61999bfc35243bc810e59ef0c0f39bd79eb59030ab2Ecco Park                break;
62099bfc35243bc810e59ef0c0f39bd79eb59030ab2Ecco Park
62199bfc35243bc810e59ef0c0f39bd79eb59030ab2Ecco Park            case PS_DATA:
62299bfc35243bc810e59ef0c0f39bd79eb59030ab2Ecco Park            if (status.line_count == 0)
62399bfc35243bc810e59ef0c0f39bd79eb59030ab2Ecco Park                if (get_input_format(ptr, &format) < 0)
62499bfc35243bc810e59ef0c0f39bd79eb59030ab2Ecco Park                    return -EILSEQ;
62599bfc35243bc810e59ef0c0f39bd79eb59030ab2Ecco Park
62699bfc35243bc810e59ef0c0f39bd79eb59030ab2Ecco Park            __skip_space(ptr);
62799bfc35243bc810e59ef0c0f39bd79eb59030ab2Ecco Park
62899bfc35243bc810e59ef0c0f39bd79eb59030ab2Ecco Park            status.char_cnt = update_char_count(ptr);
62999bfc35243bc810e59ef0c0f39bd79eb59030ab2Ecco Park
63099bfc35243bc810e59ef0c0f39bd79eb59030ab2Ecco Park            read_count = (byte_count > ENTRY_PER_LINE) ?
63199bfc35243bc810e59ef0c0f39bd79eb59030ab2Ecco Park            ENTRY_PER_LINE : byte_count;
63299bfc35243bc810e59ef0c0f39bd79eb59030ab2Ecco Park
63399bfc35243bc810e59ef0c0f39bd79eb59030ab2Ecco Park            if (format.type == PS_HEX && format.array == TRUE) {
63499bfc35243bc810e59ef0c0f39bd79eb59030ab2Ecco Park                while (read_count > 0) {
63599bfc35243bc810e59ef0c0f39bd79eb59030ab2Ecco Park                    update_tag_data(tag, &status, ptr);
63699bfc35243bc810e59ef0c0f39bd79eb59030ab2Ecco Park                    read_count -= 2;
63799bfc35243bc810e59ef0c0f39bd79eb59030ab2Ecco Park                }
63899bfc35243bc810e59ef0c0f39bd79eb59030ab2Ecco Park
63999bfc35243bc810e59ef0c0f39bd79eb59030ab2Ecco Park                if (byte_count > ENTRY_PER_LINE)
64099bfc35243bc810e59ef0c0f39bd79eb59030ab2Ecco Park                    byte_count -= ENTRY_PER_LINE;
64199bfc35243bc810e59ef0c0f39bd79eb59030ab2Ecco Park                else
64299bfc35243bc810e59ef0c0f39bd79eb59030ab2Ecco Park                    byte_count = 0;
64399bfc35243bc810e59ef0c0f39bd79eb59030ab2Ecco Park            }
64499bfc35243bc810e59ef0c0f39bd79eb59030ab2Ecco Park
64599bfc35243bc810e59ef0c0f39bd79eb59030ab2Ecco Park            status.line_count++;
64699bfc35243bc810e59ef0c0f39bd79eb59030ab2Ecco Park
64799bfc35243bc810e59ef0c0f39bd79eb59030ab2Ecco Park            if (byte_count == 0)
64899bfc35243bc810e59ef0c0f39bd79eb59030ab2Ecco Park                memset(&status, 0x00, sizeof(struct tag_info));
64999bfc35243bc810e59ef0c0f39bd79eb59030ab2Ecco Park
65099bfc35243bc810e59ef0c0f39bd79eb59030ab2Ecco Park            if (status.section == PS_UNDEF)
65199bfc35243bc810e59ef0c0f39bd79eb59030ab2Ecco Park                tag_cnt++;
65299bfc35243bc810e59ef0c0f39bd79eb59030ab2Ecco Park
65399bfc35243bc810e59ef0c0f39bd79eb59030ab2Ecco Park            if (tag_cnt == MAX_TAGS)
65499bfc35243bc810e59ef0c0f39bd79eb59030ab2Ecco Park                return -EILSEQ;
65599bfc35243bc810e59ef0c0f39bd79eb59030ab2Ecco Park            break;
65699bfc35243bc810e59ef0c0f39bd79eb59030ab2Ecco Park        }
65799bfc35243bc810e59ef0c0f39bd79eb59030ab2Ecco Park    } while (ptr);
65899bfc35243bc810e59ef0c0f39bd79eb59030ab2Ecco Park
65999bfc35243bc810e59ef0c0f39bd79eb59030ab2Ecco Park    return tag_cnt;
66099bfc35243bc810e59ef0c0f39bd79eb59030ab2Ecco Park}
66199bfc35243bc810e59ef0c0f39bd79eb59030ab2Ecco Park
66299bfc35243bc810e59ef0c0f39bd79eb59030ab2Ecco Park#define PS_RAM_SIZE 2048
66399bfc35243bc810e59ef0c0f39bd79eb59030ab2Ecco Park
66499bfc35243bc810e59ef0c0f39bd79eb59030ab2Ecco Parkstatic int ps_config_download(int fd, int tag_count)
66599bfc35243bc810e59ef0c0f39bd79eb59030ab2Ecco Park{
66699bfc35243bc810e59ef0c0f39bd79eb59030ab2Ecco Park    if (write_ps_cmd(fd, PS_RESET, PS_RAM_SIZE) < 0)
66799bfc35243bc810e59ef0c0f39bd79eb59030ab2Ecco Park        return -1;
66899bfc35243bc810e59ef0c0f39bd79eb59030ab2Ecco Park
66999bfc35243bc810e59ef0c0f39bd79eb59030ab2Ecco Park    if (tag_count > 0)
67099bfc35243bc810e59ef0c0f39bd79eb59030ab2Ecco Park        if (write_ps_cmd(fd, PS_WRITE, tag_count) < 0)
67199bfc35243bc810e59ef0c0f39bd79eb59030ab2Ecco Park            return -1;
67299bfc35243bc810e59ef0c0f39bd79eb59030ab2Ecco Park    return 0;
67399bfc35243bc810e59ef0c0f39bd79eb59030ab2Ecco Park}
67499bfc35243bc810e59ef0c0f39bd79eb59030ab2Ecco Park
67599bfc35243bc810e59ef0c0f39bd79eb59030ab2Ecco Parkstatic int write_bdaddr(int pConfig, char *bdaddr)
67699bfc35243bc810e59ef0c0f39bd79eb59030ab2Ecco Park{
67799bfc35243bc810e59ef0c0f39bd79eb59030ab2Ecco Park    uint8_t *event;
67899bfc35243bc810e59ef0c0f39bd79eb59030ab2Ecco Park    int err;
67999bfc35243bc810e59ef0c0f39bd79eb59030ab2Ecco Park    uint8_t cmd[13];
68099bfc35243bc810e59ef0c0f39bd79eb59030ab2Ecco Park    uint8_t *ptr = cmd;
68199bfc35243bc810e59ef0c0f39bd79eb59030ab2Ecco Park    hci_command_hdr *ch = (void *)cmd;
68299bfc35243bc810e59ef0c0f39bd79eb59030ab2Ecco Park
68399bfc35243bc810e59ef0c0f39bd79eb59030ab2Ecco Park    memset(cmd, 0, sizeof(cmd));
68499bfc35243bc810e59ef0c0f39bd79eb59030ab2Ecco Park
68599bfc35243bc810e59ef0c0f39bd79eb59030ab2Ecco Park    ch->opcode = htobs(cmd_opcode_pack(HCI_VENDOR_CMD_OGF,
68699bfc35243bc810e59ef0c0f39bd79eb59030ab2Ecco Park        HCI_PS_CMD_OCF));
68799bfc35243bc810e59ef0c0f39bd79eb59030ab2Ecco Park    ch->plen = 10;
68899bfc35243bc810e59ef0c0f39bd79eb59030ab2Ecco Park    ptr += HCI_COMMAND_HDR_SIZE;
68999bfc35243bc810e59ef0c0f39bd79eb59030ab2Ecco Park
69099bfc35243bc810e59ef0c0f39bd79eb59030ab2Ecco Park    ptr[0] = 0x01;
69199bfc35243bc810e59ef0c0f39bd79eb59030ab2Ecco Park    ptr[1] = 0x01;
69299bfc35243bc810e59ef0c0f39bd79eb59030ab2Ecco Park    ptr[2] = 0x00;
69399bfc35243bc810e59ef0c0f39bd79eb59030ab2Ecco Park    ptr[3] = 0x06;
69499bfc35243bc810e59ef0c0f39bd79eb59030ab2Ecco Park
69599bfc35243bc810e59ef0c0f39bd79eb59030ab2Ecco Park    convert_bdaddr(bdaddr, (char *)&ptr[4]);
69699bfc35243bc810e59ef0c0f39bd79eb59030ab2Ecco Park
69799bfc35243bc810e59ef0c0f39bd79eb59030ab2Ecco Park    err = send_hci_cmd_sync(pConfig, cmd, sizeof(cmd), &event);
69899bfc35243bc810e59ef0c0f39bd79eb59030ab2Ecco Park    if (err < 0)
69999bfc35243bc810e59ef0c0f39bd79eb59030ab2Ecco Park        return err;
70099bfc35243bc810e59ef0c0f39bd79eb59030ab2Ecco Park
70199bfc35243bc810e59ef0c0f39bd79eb59030ab2Ecco Park    err = read_ps_event(event, HCI_PS_CMD_OCF);
70299bfc35243bc810e59ef0c0f39bd79eb59030ab2Ecco Park
70399bfc35243bc810e59ef0c0f39bd79eb59030ab2Ecco Park    free(event);
70499bfc35243bc810e59ef0c0f39bd79eb59030ab2Ecco Park
70599bfc35243bc810e59ef0c0f39bd79eb59030ab2Ecco Park    return err;
70699bfc35243bc810e59ef0c0f39bd79eb59030ab2Ecco Park}
70799bfc35243bc810e59ef0c0f39bd79eb59030ab2Ecco Park
70899bfc35243bc810e59ef0c0f39bd79eb59030ab2Ecco Parkstatic void write_bdaddr_from_file(int rom_version, int fd)
70999bfc35243bc810e59ef0c0f39bd79eb59030ab2Ecco Park{
71099bfc35243bc810e59ef0c0f39bd79eb59030ab2Ecco Park    FILE *stream;
71199bfc35243bc810e59ef0c0f39bd79eb59030ab2Ecco Park    char bdaddr[PATH_MAX];
71299bfc35243bc810e59ef0c0f39bd79eb59030ab2Ecco Park    char bdaddr_file[PATH_MAX];
71399bfc35243bc810e59ef0c0f39bd79eb59030ab2Ecco Park
71499bfc35243bc810e59ef0c0f39bd79eb59030ab2Ecco Park    snprintf(bdaddr_file, MAXPATHLEN, "%s%x/%s",
71599bfc35243bc810e59ef0c0f39bd79eb59030ab2Ecco Park    FW_PATH, rom_version, BDADDR_FILE);
71699bfc35243bc810e59ef0c0f39bd79eb59030ab2Ecco Park
71799bfc35243bc810e59ef0c0f39bd79eb59030ab2Ecco Park    stream = fopen(bdaddr_file, "r");
71899bfc35243bc810e59ef0c0f39bd79eb59030ab2Ecco Park    if (!stream)
71999bfc35243bc810e59ef0c0f39bd79eb59030ab2Ecco Park       return;
72099bfc35243bc810e59ef0c0f39bd79eb59030ab2Ecco Park
72199bfc35243bc810e59ef0c0f39bd79eb59030ab2Ecco Park    if (fgets(bdaddr, PATH_MAX - 1, stream))
72299bfc35243bc810e59ef0c0f39bd79eb59030ab2Ecco Park        write_bdaddr(fd, bdaddr);
72399bfc35243bc810e59ef0c0f39bd79eb59030ab2Ecco Park
72499bfc35243bc810e59ef0c0f39bd79eb59030ab2Ecco Park    fclose(stream);
72599bfc35243bc810e59ef0c0f39bd79eb59030ab2Ecco Park}
72699bfc35243bc810e59ef0c0f39bd79eb59030ab2Ecco Park
72799bfc35243bc810e59ef0c0f39bd79eb59030ab2Ecco Park#define HCI_EVT_CMD_CMPL_OPCODE                 3
72899bfc35243bc810e59ef0c0f39bd79eb59030ab2Ecco Park#define HCI_EVT_CMD_CMPL_STATUS_RET_BYTE        5
72999bfc35243bc810e59ef0c0f39bd79eb59030ab2Ecco Park
73099bfc35243bc810e59ef0c0f39bd79eb59030ab2Ecco Parkvoid baswap(bdaddr_t *dst, const bdaddr_t *src)
73199bfc35243bc810e59ef0c0f39bd79eb59030ab2Ecco Park{
73299bfc35243bc810e59ef0c0f39bd79eb59030ab2Ecco Park    register unsigned char *d = (unsigned char *) dst;
73399bfc35243bc810e59ef0c0f39bd79eb59030ab2Ecco Park    register const unsigned char *s = (const unsigned char *) src;
73499bfc35243bc810e59ef0c0f39bd79eb59030ab2Ecco Park    register int i;
73599bfc35243bc810e59ef0c0f39bd79eb59030ab2Ecco Park    for (i = 0; i < 6; i++)
73699bfc35243bc810e59ef0c0f39bd79eb59030ab2Ecco Park        d[i] = s[5-i];
73799bfc35243bc810e59ef0c0f39bd79eb59030ab2Ecco Park}
73899bfc35243bc810e59ef0c0f39bd79eb59030ab2Ecco Park
73999bfc35243bc810e59ef0c0f39bd79eb59030ab2Ecco Park
74099bfc35243bc810e59ef0c0f39bd79eb59030ab2Ecco Parkint str2ba(const char *str, bdaddr_t *ba)
74199bfc35243bc810e59ef0c0f39bd79eb59030ab2Ecco Park{
74299bfc35243bc810e59ef0c0f39bd79eb59030ab2Ecco Park    uint8_t b[6];
74399bfc35243bc810e59ef0c0f39bd79eb59030ab2Ecco Park    const char *ptr = str;
74499bfc35243bc810e59ef0c0f39bd79eb59030ab2Ecco Park    int i;
74599bfc35243bc810e59ef0c0f39bd79eb59030ab2Ecco Park
74699bfc35243bc810e59ef0c0f39bd79eb59030ab2Ecco Park    for (i = 0; i < 6; i++) {
74799bfc35243bc810e59ef0c0f39bd79eb59030ab2Ecco Park        b[i] = (uint8_t) strtol(ptr, NULL, 16);
74899bfc35243bc810e59ef0c0f39bd79eb59030ab2Ecco Park        ptr = strchr(ptr, ':');
74999bfc35243bc810e59ef0c0f39bd79eb59030ab2Ecco Park        if (i != 5 && !ptr)
75099bfc35243bc810e59ef0c0f39bd79eb59030ab2Ecco Park            ptr = ":00:00:00:00:00";
75199bfc35243bc810e59ef0c0f39bd79eb59030ab2Ecco Park        ptr++;
75299bfc35243bc810e59ef0c0f39bd79eb59030ab2Ecco Park    }
75399bfc35243bc810e59ef0c0f39bd79eb59030ab2Ecco Park    baswap(ba, (bdaddr_t *) b);
75499bfc35243bc810e59ef0c0f39bd79eb59030ab2Ecco Park    return 0;
75599bfc35243bc810e59ef0c0f39bd79eb59030ab2Ecco Park}
75699bfc35243bc810e59ef0c0f39bd79eb59030ab2Ecco Park
75799bfc35243bc810e59ef0c0f39bd79eb59030ab2Ecco Park#define DEV_REGISTER      0x4FFC
75899bfc35243bc810e59ef0c0f39bd79eb59030ab2Ecco Park#define GET_DEV_TYPE_OCF  0x05
75999bfc35243bc810e59ef0c0f39bd79eb59030ab2Ecco Park
76099bfc35243bc810e59ef0c0f39bd79eb59030ab2Ecco Parkstatic int get_device_type(int dev, uint32_t *code)
76199bfc35243bc810e59ef0c0f39bd79eb59030ab2Ecco Park{
76299bfc35243bc810e59ef0c0f39bd79eb59030ab2Ecco Park    uint8_t cmd[8] = {0};
76399bfc35243bc810e59ef0c0f39bd79eb59030ab2Ecco Park    uint8_t *event;
76499bfc35243bc810e59ef0c0f39bd79eb59030ab2Ecco Park    uint32_t reg;
76599bfc35243bc810e59ef0c0f39bd79eb59030ab2Ecco Park    int err;
76699bfc35243bc810e59ef0c0f39bd79eb59030ab2Ecco Park    uint8_t *ptr = cmd;
76799bfc35243bc810e59ef0c0f39bd79eb59030ab2Ecco Park    hci_command_hdr *ch = (void *)cmd;
76899bfc35243bc810e59ef0c0f39bd79eb59030ab2Ecco Park
76999bfc35243bc810e59ef0c0f39bd79eb59030ab2Ecco Park    ch->opcode = htobs(cmd_opcode_pack(HCI_VENDOR_CMD_OGF,
77099bfc35243bc810e59ef0c0f39bd79eb59030ab2Ecco Park        GET_DEV_TYPE_OCF));
77199bfc35243bc810e59ef0c0f39bd79eb59030ab2Ecco Park    ch->plen = 5;
77299bfc35243bc810e59ef0c0f39bd79eb59030ab2Ecco Park    ptr += HCI_COMMAND_HDR_SIZE;
77399bfc35243bc810e59ef0c0f39bd79eb59030ab2Ecco Park
77499bfc35243bc810e59ef0c0f39bd79eb59030ab2Ecco Park    ptr[0] = (uint8_t)DEV_REGISTER;
77599bfc35243bc810e59ef0c0f39bd79eb59030ab2Ecco Park    ptr[1] = (uint8_t)DEV_REGISTER >> 8;
77699bfc35243bc810e59ef0c0f39bd79eb59030ab2Ecco Park    ptr[2] = (uint8_t)DEV_REGISTER >> 16;
77799bfc35243bc810e59ef0c0f39bd79eb59030ab2Ecco Park    ptr[3] = (uint8_t)DEV_REGISTER >> 24;
77899bfc35243bc810e59ef0c0f39bd79eb59030ab2Ecco Park    ptr[4] = 0x04;
77999bfc35243bc810e59ef0c0f39bd79eb59030ab2Ecco Park
78099bfc35243bc810e59ef0c0f39bd79eb59030ab2Ecco Park    err = send_hci_cmd_sync(dev, cmd, sizeof(cmd), &event);
78199bfc35243bc810e59ef0c0f39bd79eb59030ab2Ecco Park    if (err < 0)
78299bfc35243bc810e59ef0c0f39bd79eb59030ab2Ecco Park        return err;
78399bfc35243bc810e59ef0c0f39bd79eb59030ab2Ecco Park
78499bfc35243bc810e59ef0c0f39bd79eb59030ab2Ecco Park    err = read_ps_event(event, GET_DEV_TYPE_OCF);
78599bfc35243bc810e59ef0c0f39bd79eb59030ab2Ecco Park    if (err < 0)
78699bfc35243bc810e59ef0c0f39bd79eb59030ab2Ecco Park        goto cleanup;
78799bfc35243bc810e59ef0c0f39bd79eb59030ab2Ecco Park
78899bfc35243bc810e59ef0c0f39bd79eb59030ab2Ecco Park    reg = event[10];
78999bfc35243bc810e59ef0c0f39bd79eb59030ab2Ecco Park    reg = (reg << 8) | event[9];
79099bfc35243bc810e59ef0c0f39bd79eb59030ab2Ecco Park    reg = (reg << 8) | event[8];
79199bfc35243bc810e59ef0c0f39bd79eb59030ab2Ecco Park    reg = (reg << 8) | event[7];
79299bfc35243bc810e59ef0c0f39bd79eb59030ab2Ecco Park    *code = reg;
79399bfc35243bc810e59ef0c0f39bd79eb59030ab2Ecco Park
79499bfc35243bc810e59ef0c0f39bd79eb59030ab2Ecco Parkcleanup:
79599bfc35243bc810e59ef0c0f39bd79eb59030ab2Ecco Park    free(event);
79699bfc35243bc810e59ef0c0f39bd79eb59030ab2Ecco Park
79799bfc35243bc810e59ef0c0f39bd79eb59030ab2Ecco Park    return err;
79899bfc35243bc810e59ef0c0f39bd79eb59030ab2Ecco Park}
79999bfc35243bc810e59ef0c0f39bd79eb59030ab2Ecco Park
80099bfc35243bc810e59ef0c0f39bd79eb59030ab2Ecco Park#define GET_VERSION_OCF 0x1E
80199bfc35243bc810e59ef0c0f39bd79eb59030ab2Ecco Park
80299bfc35243bc810e59ef0c0f39bd79eb59030ab2Ecco Parkstatic int read_ath3k_version(int pConfig, uint32_t *rom_version,
80399bfc35243bc810e59ef0c0f39bd79eb59030ab2Ecco Park    uint32_t *build_version)
80499bfc35243bc810e59ef0c0f39bd79eb59030ab2Ecco Park{
80599bfc35243bc810e59ef0c0f39bd79eb59030ab2Ecco Park    uint8_t cmd[3] = {0};
80699bfc35243bc810e59ef0c0f39bd79eb59030ab2Ecco Park    uint8_t *event;
80799bfc35243bc810e59ef0c0f39bd79eb59030ab2Ecco Park    int err;
80899bfc35243bc810e59ef0c0f39bd79eb59030ab2Ecco Park    int status;
80999bfc35243bc810e59ef0c0f39bd79eb59030ab2Ecco Park    hci_command_hdr *ch = (void *)cmd;
81099bfc35243bc810e59ef0c0f39bd79eb59030ab2Ecco Park
81199bfc35243bc810e59ef0c0f39bd79eb59030ab2Ecco Park    ch->opcode = htobs(cmd_opcode_pack(HCI_VENDOR_CMD_OGF,
81299bfc35243bc810e59ef0c0f39bd79eb59030ab2Ecco Park    GET_VERSION_OCF));
81399bfc35243bc810e59ef0c0f39bd79eb59030ab2Ecco Park    ch->plen = 0;
81499bfc35243bc810e59ef0c0f39bd79eb59030ab2Ecco Park
81599bfc35243bc810e59ef0c0f39bd79eb59030ab2Ecco Park    err = send_hci_cmd_sync(pConfig, cmd, sizeof(cmd), &event);
81699bfc35243bc810e59ef0c0f39bd79eb59030ab2Ecco Park    if (err < 0)
81799bfc35243bc810e59ef0c0f39bd79eb59030ab2Ecco Park        return err;
81899bfc35243bc810e59ef0c0f39bd79eb59030ab2Ecco Park
81999bfc35243bc810e59ef0c0f39bd79eb59030ab2Ecco Park    err = read_ps_event(event, GET_VERSION_OCF);
82099bfc35243bc810e59ef0c0f39bd79eb59030ab2Ecco Park    if (err < 0)
82199bfc35243bc810e59ef0c0f39bd79eb59030ab2Ecco Park        goto cleanup;
82299bfc35243bc810e59ef0c0f39bd79eb59030ab2Ecco Park
82399bfc35243bc810e59ef0c0f39bd79eb59030ab2Ecco Park    status = event[10];
82499bfc35243bc810e59ef0c0f39bd79eb59030ab2Ecco Park    status = (status << 8) | event[9];
82599bfc35243bc810e59ef0c0f39bd79eb59030ab2Ecco Park    status = (status << 8) | event[8];
82699bfc35243bc810e59ef0c0f39bd79eb59030ab2Ecco Park    status = (status << 8) | event[7];
82799bfc35243bc810e59ef0c0f39bd79eb59030ab2Ecco Park    *rom_version = status;
82899bfc35243bc810e59ef0c0f39bd79eb59030ab2Ecco Park
82999bfc35243bc810e59ef0c0f39bd79eb59030ab2Ecco Park    status = event[14];
83099bfc35243bc810e59ef0c0f39bd79eb59030ab2Ecco Park    status = (status << 8) | event[13];
83199bfc35243bc810e59ef0c0f39bd79eb59030ab2Ecco Park    status = (status << 8) | event[12];
83299bfc35243bc810e59ef0c0f39bd79eb59030ab2Ecco Park    status = (status << 8) | event[11];
83399bfc35243bc810e59ef0c0f39bd79eb59030ab2Ecco Park    *build_version = status;
83499bfc35243bc810e59ef0c0f39bd79eb59030ab2Ecco Park
83599bfc35243bc810e59ef0c0f39bd79eb59030ab2Ecco Parkcleanup:
83699bfc35243bc810e59ef0c0f39bd79eb59030ab2Ecco Park    free(event);
83799bfc35243bc810e59ef0c0f39bd79eb59030ab2Ecco Park
83899bfc35243bc810e59ef0c0f39bd79eb59030ab2Ecco Park    return err;
83999bfc35243bc810e59ef0c0f39bd79eb59030ab2Ecco Park}
84099bfc35243bc810e59ef0c0f39bd79eb59030ab2Ecco Park
84199bfc35243bc810e59ef0c0f39bd79eb59030ab2Ecco Park#define VERIFY_CRC   9
84299bfc35243bc810e59ef0c0f39bd79eb59030ab2Ecco Park#define PS_REGION    1
84399bfc35243bc810e59ef0c0f39bd79eb59030ab2Ecco Park#define PATCH_REGION 2
84499bfc35243bc810e59ef0c0f39bd79eb59030ab2Ecco Park
84599bfc35243bc810e59ef0c0f39bd79eb59030ab2Ecco Parkstatic int get_ath3k_crc(int dev)
84699bfc35243bc810e59ef0c0f39bd79eb59030ab2Ecco Park{
84799bfc35243bc810e59ef0c0f39bd79eb59030ab2Ecco Park    uint8_t cmd[7] = {0};
84899bfc35243bc810e59ef0c0f39bd79eb59030ab2Ecco Park    uint8_t *event;
84999bfc35243bc810e59ef0c0f39bd79eb59030ab2Ecco Park    int err;
85099bfc35243bc810e59ef0c0f39bd79eb59030ab2Ecco Park
85199bfc35243bc810e59ef0c0f39bd79eb59030ab2Ecco Park    load_hci_ps_hdr(cmd, VERIFY_CRC, 0, PS_REGION | PATCH_REGION);
85299bfc35243bc810e59ef0c0f39bd79eb59030ab2Ecco Park
85399bfc35243bc810e59ef0c0f39bd79eb59030ab2Ecco Park    err = send_hci_cmd_sync(dev, cmd, sizeof(cmd), &event);
85499bfc35243bc810e59ef0c0f39bd79eb59030ab2Ecco Park    if (err < 0)
85599bfc35243bc810e59ef0c0f39bd79eb59030ab2Ecco Park        return err;
85699bfc35243bc810e59ef0c0f39bd79eb59030ab2Ecco Park    /* Send error code if CRC check patched */
85799bfc35243bc810e59ef0c0f39bd79eb59030ab2Ecco Park    if (read_ps_event(event, HCI_PS_CMD_OCF) >= 0)
85899bfc35243bc810e59ef0c0f39bd79eb59030ab2Ecco Park        err = -EILSEQ;
85999bfc35243bc810e59ef0c0f39bd79eb59030ab2Ecco Park
86099bfc35243bc810e59ef0c0f39bd79eb59030ab2Ecco Park    free(event);
86199bfc35243bc810e59ef0c0f39bd79eb59030ab2Ecco Park
86299bfc35243bc810e59ef0c0f39bd79eb59030ab2Ecco Park    return err;
86399bfc35243bc810e59ef0c0f39bd79eb59030ab2Ecco Park}
86499bfc35243bc810e59ef0c0f39bd79eb59030ab2Ecco Park
86599bfc35243bc810e59ef0c0f39bd79eb59030ab2Ecco Park#define SET_PATCH_RAM_ID        0x0D
86699bfc35243bc810e59ef0c0f39bd79eb59030ab2Ecco Park#define SET_PATCH_RAM_CMD_SIZE  11
86799bfc35243bc810e59ef0c0f39bd79eb59030ab2Ecco Park#define ADDRESS_LEN             4
86899bfc35243bc810e59ef0c0f39bd79eb59030ab2Ecco Parkstatic int set_patch_ram(int dev, char *patch_loc, int len)
86999bfc35243bc810e59ef0c0f39bd79eb59030ab2Ecco Park{
87099bfc35243bc810e59ef0c0f39bd79eb59030ab2Ecco Park    int err;
87199bfc35243bc810e59ef0c0f39bd79eb59030ab2Ecco Park    uint8_t cmd[20] = {0};
87299bfc35243bc810e59ef0c0f39bd79eb59030ab2Ecco Park    int i, j;
87399bfc35243bc810e59ef0c0f39bd79eb59030ab2Ecco Park    char loc_byte[3];
87499bfc35243bc810e59ef0c0f39bd79eb59030ab2Ecco Park    uint8_t *event;
87599bfc35243bc810e59ef0c0f39bd79eb59030ab2Ecco Park    uint8_t *loc_ptr = &cmd[7];
87699bfc35243bc810e59ef0c0f39bd79eb59030ab2Ecco Park
87799bfc35243bc810e59ef0c0f39bd79eb59030ab2Ecco Park    if (!patch_loc)
87899bfc35243bc810e59ef0c0f39bd79eb59030ab2Ecco Park        return -1;
87999bfc35243bc810e59ef0c0f39bd79eb59030ab2Ecco Park
88099bfc35243bc810e59ef0c0f39bd79eb59030ab2Ecco Park    loc_byte[2] = '\0';
88199bfc35243bc810e59ef0c0f39bd79eb59030ab2Ecco Park
88299bfc35243bc810e59ef0c0f39bd79eb59030ab2Ecco Park    load_hci_ps_hdr(cmd, SET_PATCH_RAM_ID, ADDRESS_LEN, 0);
88399bfc35243bc810e59ef0c0f39bd79eb59030ab2Ecco Park
88499bfc35243bc810e59ef0c0f39bd79eb59030ab2Ecco Park    for (i = 0, j = 3; i < 4; i++, j--) {
88599bfc35243bc810e59ef0c0f39bd79eb59030ab2Ecco Park        loc_byte[0] = patch_loc[0];
88699bfc35243bc810e59ef0c0f39bd79eb59030ab2Ecco Park        loc_byte[1] = patch_loc[1];
88799bfc35243bc810e59ef0c0f39bd79eb59030ab2Ecco Park        loc_ptr[j] = strtol(loc_byte, NULL, 16);
88899bfc35243bc810e59ef0c0f39bd79eb59030ab2Ecco Park        patch_loc += 2;
88999bfc35243bc810e59ef0c0f39bd79eb59030ab2Ecco Park    }
89099bfc35243bc810e59ef0c0f39bd79eb59030ab2Ecco Park
89199bfc35243bc810e59ef0c0f39bd79eb59030ab2Ecco Park    err = send_hci_cmd_sync(dev, cmd, SET_PATCH_RAM_CMD_SIZE, &event);
89299bfc35243bc810e59ef0c0f39bd79eb59030ab2Ecco Park    if (err < 0)
89399bfc35243bc810e59ef0c0f39bd79eb59030ab2Ecco Park        return err;
89499bfc35243bc810e59ef0c0f39bd79eb59030ab2Ecco Park
89599bfc35243bc810e59ef0c0f39bd79eb59030ab2Ecco Park    err = read_ps_event(event, HCI_PS_CMD_OCF);
89699bfc35243bc810e59ef0c0f39bd79eb59030ab2Ecco Park
89799bfc35243bc810e59ef0c0f39bd79eb59030ab2Ecco Park    free(event);
89899bfc35243bc810e59ef0c0f39bd79eb59030ab2Ecco Park
89999bfc35243bc810e59ef0c0f39bd79eb59030ab2Ecco Park    return err;
90099bfc35243bc810e59ef0c0f39bd79eb59030ab2Ecco Park}
90199bfc35243bc810e59ef0c0f39bd79eb59030ab2Ecco Park
90299bfc35243bc810e59ef0c0f39bd79eb59030ab2Ecco Park#define PATCH_LOC_KEY    "DA:"
90399bfc35243bc810e59ef0c0f39bd79eb59030ab2Ecco Park#define PATCH_LOC_STRING_LEN    8
90499bfc35243bc810e59ef0c0f39bd79eb59030ab2Ecco Parkstatic int ps_patch_download(int fd, FILE *stream)
90599bfc35243bc810e59ef0c0f39bd79eb59030ab2Ecco Park{
90699bfc35243bc810e59ef0c0f39bd79eb59030ab2Ecco Park    char byte[3];
90799bfc35243bc810e59ef0c0f39bd79eb59030ab2Ecco Park    char ptr[MAX_PATCH_CMD + 1];
90899bfc35243bc810e59ef0c0f39bd79eb59030ab2Ecco Park    int byte_cnt;
90999bfc35243bc810e59ef0c0f39bd79eb59030ab2Ecco Park    int patch_count = 0;
91099bfc35243bc810e59ef0c0f39bd79eb59030ab2Ecco Park    char patch_loc[PATCH_LOC_STRING_LEN + 1];
91199bfc35243bc810e59ef0c0f39bd79eb59030ab2Ecco Park
91299bfc35243bc810e59ef0c0f39bd79eb59030ab2Ecco Park    byte[2] = '\0';
91399bfc35243bc810e59ef0c0f39bd79eb59030ab2Ecco Park
91499bfc35243bc810e59ef0c0f39bd79eb59030ab2Ecco Park    while (fgets(ptr, MAX_PATCH_CMD, stream)) {
91599bfc35243bc810e59ef0c0f39bd79eb59030ab2Ecco Park        if (strlen(ptr) <= 1)
91699bfc35243bc810e59ef0c0f39bd79eb59030ab2Ecco Park            continue;
91799bfc35243bc810e59ef0c0f39bd79eb59030ab2Ecco Park        else if (strstr(ptr, PATCH_LOC_KEY) == ptr) {
91899bfc35243bc810e59ef0c0f39bd79eb59030ab2Ecco Park            strlcpy(patch_loc, &ptr[sizeof(PATCH_LOC_KEY) - 1],
91999bfc35243bc810e59ef0c0f39bd79eb59030ab2Ecco Park                PATCH_LOC_STRING_LEN);
92099bfc35243bc810e59ef0c0f39bd79eb59030ab2Ecco Park            if (set_patch_ram(fd, patch_loc, sizeof(patch_loc)) < 0)
92199bfc35243bc810e59ef0c0f39bd79eb59030ab2Ecco Park                return -1;
92299bfc35243bc810e59ef0c0f39bd79eb59030ab2Ecco Park        } else if (isxdigit(ptr[0]))
92399bfc35243bc810e59ef0c0f39bd79eb59030ab2Ecco Park            break;
92499bfc35243bc810e59ef0c0f39bd79eb59030ab2Ecco Park        else
92599bfc35243bc810e59ef0c0f39bd79eb59030ab2Ecco Park        return -1;
92699bfc35243bc810e59ef0c0f39bd79eb59030ab2Ecco Park    }
92799bfc35243bc810e59ef0c0f39bd79eb59030ab2Ecco Park
92899bfc35243bc810e59ef0c0f39bd79eb59030ab2Ecco Park    byte_cnt = strtol(ptr, NULL, 16);
92999bfc35243bc810e59ef0c0f39bd79eb59030ab2Ecco Park
93099bfc35243bc810e59ef0c0f39bd79eb59030ab2Ecco Park    while (byte_cnt > 0) {
93199bfc35243bc810e59ef0c0f39bd79eb59030ab2Ecco Park        int i;
93299bfc35243bc810e59ef0c0f39bd79eb59030ab2Ecco Park        uint8_t cmd[HCI_MAX_CMD_SIZE] = {0};
93399bfc35243bc810e59ef0c0f39bd79eb59030ab2Ecco Park        struct patch_entry patch;
93499bfc35243bc810e59ef0c0f39bd79eb59030ab2Ecco Park
93599bfc35243bc810e59ef0c0f39bd79eb59030ab2Ecco Park        if (byte_cnt > MAX_PATCH_CMD)
93699bfc35243bc810e59ef0c0f39bd79eb59030ab2Ecco Park            patch.len = MAX_PATCH_CMD;
93799bfc35243bc810e59ef0c0f39bd79eb59030ab2Ecco Park        else
93899bfc35243bc810e59ef0c0f39bd79eb59030ab2Ecco Park            patch.len = byte_cnt;
93999bfc35243bc810e59ef0c0f39bd79eb59030ab2Ecco Park
94099bfc35243bc810e59ef0c0f39bd79eb59030ab2Ecco Park        for (i = 0; i < patch.len; i++) {
94199bfc35243bc810e59ef0c0f39bd79eb59030ab2Ecco Park            if (!fgets(byte, 3, stream))
94299bfc35243bc810e59ef0c0f39bd79eb59030ab2Ecco Park                return -1;
94399bfc35243bc810e59ef0c0f39bd79eb59030ab2Ecco Park
94499bfc35243bc810e59ef0c0f39bd79eb59030ab2Ecco Park            patch.data[i] = strtoul(byte, NULL, 16);
94599bfc35243bc810e59ef0c0f39bd79eb59030ab2Ecco Park        }
94699bfc35243bc810e59ef0c0f39bd79eb59030ab2Ecco Park
94799bfc35243bc810e59ef0c0f39bd79eb59030ab2Ecco Park        load_hci_ps_hdr(cmd, WRITE_PATCH, patch.len, patch_count);
94899bfc35243bc810e59ef0c0f39bd79eb59030ab2Ecco Park        memcpy(&cmd[HCI_PS_CMD_HDR_LEN], patch.data, patch.len);
94999bfc35243bc810e59ef0c0f39bd79eb59030ab2Ecco Park
95099bfc35243bc810e59ef0c0f39bd79eb59030ab2Ecco Park        if (write_cmd(fd, cmd, patch.len + HCI_PS_CMD_HDR_LEN) < 0)
95199bfc35243bc810e59ef0c0f39bd79eb59030ab2Ecco Park            return -1;
95299bfc35243bc810e59ef0c0f39bd79eb59030ab2Ecco Park
95399bfc35243bc810e59ef0c0f39bd79eb59030ab2Ecco Park        patch_count++;
95499bfc35243bc810e59ef0c0f39bd79eb59030ab2Ecco Park        byte_cnt = byte_cnt - MAX_PATCH_CMD;
95599bfc35243bc810e59ef0c0f39bd79eb59030ab2Ecco Park    }
95699bfc35243bc810e59ef0c0f39bd79eb59030ab2Ecco Park
95799bfc35243bc810e59ef0c0f39bd79eb59030ab2Ecco Park    if (write_ps_cmd(fd, ENABLE_PATCH, 0) < 0)
95899bfc35243bc810e59ef0c0f39bd79eb59030ab2Ecco Park        return -1;
95999bfc35243bc810e59ef0c0f39bd79eb59030ab2Ecco Park
96099bfc35243bc810e59ef0c0f39bd79eb59030ab2Ecco Park    return patch_count;
96199bfc35243bc810e59ef0c0f39bd79eb59030ab2Ecco Park}
96299bfc35243bc810e59ef0c0f39bd79eb59030ab2Ecco Park
96399bfc35243bc810e59ef0c0f39bd79eb59030ab2Ecco Parkstatic int ath_ps_download(int fd)
96499bfc35243bc810e59ef0c0f39bd79eb59030ab2Ecco Park{
96599bfc35243bc810e59ef0c0f39bd79eb59030ab2Ecco Park    int err = 0;
96699bfc35243bc810e59ef0c0f39bd79eb59030ab2Ecco Park    int tag_count;
96799bfc35243bc810e59ef0c0f39bd79eb59030ab2Ecco Park    int patch_count = 0;
96899bfc35243bc810e59ef0c0f39bd79eb59030ab2Ecco Park    uint32_t rom_version = 0;
96999bfc35243bc810e59ef0c0f39bd79eb59030ab2Ecco Park    uint32_t build_version = 0;
97099bfc35243bc810e59ef0c0f39bd79eb59030ab2Ecco Park    uint32_t dev_type = 0;
97199bfc35243bc810e59ef0c0f39bd79eb59030ab2Ecco Park    char patch_file[PATH_MAX];
97299bfc35243bc810e59ef0c0f39bd79eb59030ab2Ecco Park    char ps_file[PATH_MAX];
97399bfc35243bc810e59ef0c0f39bd79eb59030ab2Ecco Park    FILE *stream;
97499bfc35243bc810e59ef0c0f39bd79eb59030ab2Ecco Park
97599bfc35243bc810e59ef0c0f39bd79eb59030ab2Ecco Park    /*
97699bfc35243bc810e59ef0c0f39bd79eb59030ab2Ecco Park    * Verfiy firmware version. depending on it select the PS
97799bfc35243bc810e59ef0c0f39bd79eb59030ab2Ecco Park    * config file to download.
97899bfc35243bc810e59ef0c0f39bd79eb59030ab2Ecco Park    */
97999bfc35243bc810e59ef0c0f39bd79eb59030ab2Ecco Park    if (get_device_type(fd, &dev_type) < 0) {
98099bfc35243bc810e59ef0c0f39bd79eb59030ab2Ecco Park        err = -EILSEQ;
98199bfc35243bc810e59ef0c0f39bd79eb59030ab2Ecco Park        goto download_cmplete;
98299bfc35243bc810e59ef0c0f39bd79eb59030ab2Ecco Park    }
98399bfc35243bc810e59ef0c0f39bd79eb59030ab2Ecco Park
98499bfc35243bc810e59ef0c0f39bd79eb59030ab2Ecco Park    if (read_ath3k_version(fd, &rom_version, &build_version) < 0) {
98599bfc35243bc810e59ef0c0f39bd79eb59030ab2Ecco Park        err = -EILSEQ;
98699bfc35243bc810e59ef0c0f39bd79eb59030ab2Ecco Park        goto download_cmplete;
98799bfc35243bc810e59ef0c0f39bd79eb59030ab2Ecco Park    }
98899bfc35243bc810e59ef0c0f39bd79eb59030ab2Ecco Park
98999bfc35243bc810e59ef0c0f39bd79eb59030ab2Ecco Park    /* Do not download configuration if CRC passes */
99099bfc35243bc810e59ef0c0f39bd79eb59030ab2Ecco Park    if (get_ath3k_crc(fd) < 0) {
99199bfc35243bc810e59ef0c0f39bd79eb59030ab2Ecco Park        err = 0;
99299bfc35243bc810e59ef0c0f39bd79eb59030ab2Ecco Park        goto download_cmplete;
99399bfc35243bc810e59ef0c0f39bd79eb59030ab2Ecco Park    }
99499bfc35243bc810e59ef0c0f39bd79eb59030ab2Ecco Park
99599bfc35243bc810e59ef0c0f39bd79eb59030ab2Ecco Park    get_ps_file_name(dev_type, rom_version, ps_file);
99699bfc35243bc810e59ef0c0f39bd79eb59030ab2Ecco Park    get_patch_file_name(dev_type, rom_version, build_version, patch_file);
99799bfc35243bc810e59ef0c0f39bd79eb59030ab2Ecco Park
99899bfc35243bc810e59ef0c0f39bd79eb59030ab2Ecco Park    stream = fopen(ps_file, "r");
99999bfc35243bc810e59ef0c0f39bd79eb59030ab2Ecco Park    if (!stream) {
100099bfc35243bc810e59ef0c0f39bd79eb59030ab2Ecco Park        ALOGI("firmware file open error:%s, ver:%x\n",ps_file, rom_version);
100199bfc35243bc810e59ef0c0f39bd79eb59030ab2Ecco Park        if (rom_version == 0x1020201)
100299bfc35243bc810e59ef0c0f39bd79eb59030ab2Ecco Park            err = 0;
100399bfc35243bc810e59ef0c0f39bd79eb59030ab2Ecco Park        else
100499bfc35243bc810e59ef0c0f39bd79eb59030ab2Ecco Park            err	= -EILSEQ;
100599bfc35243bc810e59ef0c0f39bd79eb59030ab2Ecco Park        goto download_cmplete;
100699bfc35243bc810e59ef0c0f39bd79eb59030ab2Ecco Park    }
100799bfc35243bc810e59ef0c0f39bd79eb59030ab2Ecco Park    tag_count = ath_parse_ps(stream);
100899bfc35243bc810e59ef0c0f39bd79eb59030ab2Ecco Park
100999bfc35243bc810e59ef0c0f39bd79eb59030ab2Ecco Park    fclose(stream);
101099bfc35243bc810e59ef0c0f39bd79eb59030ab2Ecco Park
101199bfc35243bc810e59ef0c0f39bd79eb59030ab2Ecco Park    if (tag_count < 0) {
101299bfc35243bc810e59ef0c0f39bd79eb59030ab2Ecco Park        err = -EILSEQ;
101399bfc35243bc810e59ef0c0f39bd79eb59030ab2Ecco Park        goto download_cmplete;
101499bfc35243bc810e59ef0c0f39bd79eb59030ab2Ecco Park    }
101599bfc35243bc810e59ef0c0f39bd79eb59030ab2Ecco Park
101699bfc35243bc810e59ef0c0f39bd79eb59030ab2Ecco Park    /*
101799bfc35243bc810e59ef0c0f39bd79eb59030ab2Ecco Park    * It is not necessary that Patch file be available,
101899bfc35243bc810e59ef0c0f39bd79eb59030ab2Ecco Park    * continue with PS Operations if patch file is not available.
101999bfc35243bc810e59ef0c0f39bd79eb59030ab2Ecco Park    */
102099bfc35243bc810e59ef0c0f39bd79eb59030ab2Ecco Park    if (patch_file[0] == '\0')
102199bfc35243bc810e59ef0c0f39bd79eb59030ab2Ecco Park        err = 0;
102299bfc35243bc810e59ef0c0f39bd79eb59030ab2Ecco Park
102399bfc35243bc810e59ef0c0f39bd79eb59030ab2Ecco Park    stream = fopen(patch_file, "r");
102499bfc35243bc810e59ef0c0f39bd79eb59030ab2Ecco Park    if (!stream)
102599bfc35243bc810e59ef0c0f39bd79eb59030ab2Ecco Park        err = 0;
102699bfc35243bc810e59ef0c0f39bd79eb59030ab2Ecco Park    else {
102799bfc35243bc810e59ef0c0f39bd79eb59030ab2Ecco Park        patch_count = ps_patch_download(fd, stream);
102899bfc35243bc810e59ef0c0f39bd79eb59030ab2Ecco Park        fclose(stream);
102999bfc35243bc810e59ef0c0f39bd79eb59030ab2Ecco Park
103099bfc35243bc810e59ef0c0f39bd79eb59030ab2Ecco Park        if (patch_count < 0) {
103199bfc35243bc810e59ef0c0f39bd79eb59030ab2Ecco Park            err = -EILSEQ;
103299bfc35243bc810e59ef0c0f39bd79eb59030ab2Ecco Park            goto download_cmplete;
103399bfc35243bc810e59ef0c0f39bd79eb59030ab2Ecco Park        }
103499bfc35243bc810e59ef0c0f39bd79eb59030ab2Ecco Park    }
103599bfc35243bc810e59ef0c0f39bd79eb59030ab2Ecco Park
103699bfc35243bc810e59ef0c0f39bd79eb59030ab2Ecco Park    err = ps_config_download(fd, tag_count);
103799bfc35243bc810e59ef0c0f39bd79eb59030ab2Ecco Park
103899bfc35243bc810e59ef0c0f39bd79eb59030ab2Ecco Parkdownload_cmplete:
103999bfc35243bc810e59ef0c0f39bd79eb59030ab2Ecco Park    if (!err)
104099bfc35243bc810e59ef0c0f39bd79eb59030ab2Ecco Park        write_bdaddr_from_file(rom_version, fd);
104199bfc35243bc810e59ef0c0f39bd79eb59030ab2Ecco Park
104299bfc35243bc810e59ef0c0f39bd79eb59030ab2Ecco Park    return err;
104399bfc35243bc810e59ef0c0f39bd79eb59030ab2Ecco Park}
104499bfc35243bc810e59ef0c0f39bd79eb59030ab2Ecco Park
104599bfc35243bc810e59ef0c0f39bd79eb59030ab2Ecco Parkint ath3k_init(int fd, int speed, int init_speed, char *bdaddr, struct termios *ti)
104699bfc35243bc810e59ef0c0f39bd79eb59030ab2Ecco Park{
104799bfc35243bc810e59ef0c0f39bd79eb59030ab2Ecco Park    ALOGI(" %s ", __FUNCTION__);
104899bfc35243bc810e59ef0c0f39bd79eb59030ab2Ecco Park
104999bfc35243bc810e59ef0c0f39bd79eb59030ab2Ecco Park    int r;
105099bfc35243bc810e59ef0c0f39bd79eb59030ab2Ecco Park    int err = 0;
105199bfc35243bc810e59ef0c0f39bd79eb59030ab2Ecco Park    struct timespec tm = { 0, 500000};
105299bfc35243bc810e59ef0c0f39bd79eb59030ab2Ecco Park    unsigned char cmd[MAX_CMD_LEN] = {0};
105399bfc35243bc810e59ef0c0f39bd79eb59030ab2Ecco Park    unsigned char rsp[HCI_MAX_EVENT_SIZE];
105499bfc35243bc810e59ef0c0f39bd79eb59030ab2Ecco Park    unsigned char *ptr = cmd + 1;
105599bfc35243bc810e59ef0c0f39bd79eb59030ab2Ecco Park    hci_command_hdr *ch = (void *)ptr;
105699bfc35243bc810e59ef0c0f39bd79eb59030ab2Ecco Park    int flags = 0;
105799bfc35243bc810e59ef0c0f39bd79eb59030ab2Ecco Park
105899bfc35243bc810e59ef0c0f39bd79eb59030ab2Ecco Park    if (ioctl(fd, TIOCMGET, &flags) < 0) {
105999bfc35243bc810e59ef0c0f39bd79eb59030ab2Ecco Park        ALOGI("TIOCMGET failed in init\n");
106099bfc35243bc810e59ef0c0f39bd79eb59030ab2Ecco Park        return -1;
106199bfc35243bc810e59ef0c0f39bd79eb59030ab2Ecco Park    }
106299bfc35243bc810e59ef0c0f39bd79eb59030ab2Ecco Park    flags |= TIOCM_RTS;
106399bfc35243bc810e59ef0c0f39bd79eb59030ab2Ecco Park    if (ioctl(fd, TIOCMSET, &flags) < 0) {
106499bfc35243bc810e59ef0c0f39bd79eb59030ab2Ecco Park        ALOGI("TIOCMSET failed in init: HW Flow-on error\n");
106599bfc35243bc810e59ef0c0f39bd79eb59030ab2Ecco Park        return -1;
106699bfc35243bc810e59ef0c0f39bd79eb59030ab2Ecco Park    }
106799bfc35243bc810e59ef0c0f39bd79eb59030ab2Ecco Park
106899bfc35243bc810e59ef0c0f39bd79eb59030ab2Ecco Park    /* set both controller and host baud rate to maximum possible value */
106999bfc35243bc810e59ef0c0f39bd79eb59030ab2Ecco Park    err = set_cntrlr_baud(fd, speed);
107099bfc35243bc810e59ef0c0f39bd79eb59030ab2Ecco Park    ALOGI("set_cntrlr_baud : ret:%d \n", err);
107199bfc35243bc810e59ef0c0f39bd79eb59030ab2Ecco Park    if (err < 0)
107299bfc35243bc810e59ef0c0f39bd79eb59030ab2Ecco Park        return err;
107399bfc35243bc810e59ef0c0f39bd79eb59030ab2Ecco Park
107499bfc35243bc810e59ef0c0f39bd79eb59030ab2Ecco Park    err = set_speed(fd, ti, speed);
107599bfc35243bc810e59ef0c0f39bd79eb59030ab2Ecco Park    if (err < 0) {
107699bfc35243bc810e59ef0c0f39bd79eb59030ab2Ecco Park        ALOGI("Can't set required baud rate");
107799bfc35243bc810e59ef0c0f39bd79eb59030ab2Ecco Park        return err;
107899bfc35243bc810e59ef0c0f39bd79eb59030ab2Ecco Park    }
107999bfc35243bc810e59ef0c0f39bd79eb59030ab2Ecco Park
108099bfc35243bc810e59ef0c0f39bd79eb59030ab2Ecco Park    /* Download PS and patch */
108199bfc35243bc810e59ef0c0f39bd79eb59030ab2Ecco Park    r = ath_ps_download(fd);
108299bfc35243bc810e59ef0c0f39bd79eb59030ab2Ecco Park    if (r < 0) {
108399bfc35243bc810e59ef0c0f39bd79eb59030ab2Ecco Park        ALOGI("Failed to Download configuration");
108499bfc35243bc810e59ef0c0f39bd79eb59030ab2Ecco Park        err = -ETIMEDOUT;
108599bfc35243bc810e59ef0c0f39bd79eb59030ab2Ecco Park        goto failed;
108699bfc35243bc810e59ef0c0f39bd79eb59030ab2Ecco Park    }
108799bfc35243bc810e59ef0c0f39bd79eb59030ab2Ecco Park
108899bfc35243bc810e59ef0c0f39bd79eb59030ab2Ecco Park    ALOGI("ath_ps_download is done\n");
108999bfc35243bc810e59ef0c0f39bd79eb59030ab2Ecco Park
109099bfc35243bc810e59ef0c0f39bd79eb59030ab2Ecco Park    cmd[0] = HCI_COMMAND_PKT;
109199bfc35243bc810e59ef0c0f39bd79eb59030ab2Ecco Park    /* Write BDADDR */
109299bfc35243bc810e59ef0c0f39bd79eb59030ab2Ecco Park    if (bdaddr) {
109399bfc35243bc810e59ef0c0f39bd79eb59030ab2Ecco Park        ch->opcode = htobs(cmd_opcode_pack(HCI_VENDOR_CMD_OGF,
109499bfc35243bc810e59ef0c0f39bd79eb59030ab2Ecco Park        HCI_PS_CMD_OCF));
109599bfc35243bc810e59ef0c0f39bd79eb59030ab2Ecco Park        ch->plen = 10;
109699bfc35243bc810e59ef0c0f39bd79eb59030ab2Ecco Park        ptr += HCI_COMMAND_HDR_SIZE;
109799bfc35243bc810e59ef0c0f39bd79eb59030ab2Ecco Park
109899bfc35243bc810e59ef0c0f39bd79eb59030ab2Ecco Park        ptr[0] = 0x01;
109999bfc35243bc810e59ef0c0f39bd79eb59030ab2Ecco Park        ptr[1] = 0x01;
110099bfc35243bc810e59ef0c0f39bd79eb59030ab2Ecco Park        ptr[2] = 0x00;
110199bfc35243bc810e59ef0c0f39bd79eb59030ab2Ecco Park        ptr[3] = 0x06;
110299bfc35243bc810e59ef0c0f39bd79eb59030ab2Ecco Park        str2ba(bdaddr, (bdaddr_t *)(ptr + 4));
110399bfc35243bc810e59ef0c0f39bd79eb59030ab2Ecco Park
110499bfc35243bc810e59ef0c0f39bd79eb59030ab2Ecco Park        if (write(fd, cmd, WRITE_BDADDR_CMD_LEN) !=
110599bfc35243bc810e59ef0c0f39bd79eb59030ab2Ecco Park                WRITE_BDADDR_CMD_LEN) {
110699bfc35243bc810e59ef0c0f39bd79eb59030ab2Ecco Park            ALOGI("Failed to write BD_ADDR command\n");
110799bfc35243bc810e59ef0c0f39bd79eb59030ab2Ecco Park            err = -ETIMEDOUT;
110899bfc35243bc810e59ef0c0f39bd79eb59030ab2Ecco Park            goto failed;
110999bfc35243bc810e59ef0c0f39bd79eb59030ab2Ecco Park        }
111099bfc35243bc810e59ef0c0f39bd79eb59030ab2Ecco Park
111199bfc35243bc810e59ef0c0f39bd79eb59030ab2Ecco Park        if (read_hci_event(fd, rsp, sizeof(rsp)) < 0) {
111299bfc35243bc810e59ef0c0f39bd79eb59030ab2Ecco Park            ALOGI("Failed to set BD_ADDR\n");
111399bfc35243bc810e59ef0c0f39bd79eb59030ab2Ecco Park            err = -ETIMEDOUT;
111499bfc35243bc810e59ef0c0f39bd79eb59030ab2Ecco Park            goto failed;
111599bfc35243bc810e59ef0c0f39bd79eb59030ab2Ecco Park        }
111699bfc35243bc810e59ef0c0f39bd79eb59030ab2Ecco Park    }
111799bfc35243bc810e59ef0c0f39bd79eb59030ab2Ecco Park
111899bfc35243bc810e59ef0c0f39bd79eb59030ab2Ecco Park    /* Send HCI Reset */
111999bfc35243bc810e59ef0c0f39bd79eb59030ab2Ecco Park    cmd[1] = 0x03;
112099bfc35243bc810e59ef0c0f39bd79eb59030ab2Ecco Park    cmd[2] = 0x0C;
112199bfc35243bc810e59ef0c0f39bd79eb59030ab2Ecco Park    cmd[3] = 0x00;
112299bfc35243bc810e59ef0c0f39bd79eb59030ab2Ecco Park
112399bfc35243bc810e59ef0c0f39bd79eb59030ab2Ecco Park    r = write(fd, cmd, 4);
112499bfc35243bc810e59ef0c0f39bd79eb59030ab2Ecco Park    if (r != 4) {
112599bfc35243bc810e59ef0c0f39bd79eb59030ab2Ecco Park        err = -ETIMEDOUT;
112699bfc35243bc810e59ef0c0f39bd79eb59030ab2Ecco Park        goto failed;
112799bfc35243bc810e59ef0c0f39bd79eb59030ab2Ecco Park    }
112899bfc35243bc810e59ef0c0f39bd79eb59030ab2Ecco Park
112999bfc35243bc810e59ef0c0f39bd79eb59030ab2Ecco Park    nanosleep(&tm, NULL);
113099bfc35243bc810e59ef0c0f39bd79eb59030ab2Ecco Park    if (read_hci_event(fd, rsp, sizeof(rsp)) < 0) {
113199bfc35243bc810e59ef0c0f39bd79eb59030ab2Ecco Park        err = -ETIMEDOUT;
113299bfc35243bc810e59ef0c0f39bd79eb59030ab2Ecco Park        goto failed;
113399bfc35243bc810e59ef0c0f39bd79eb59030ab2Ecco Park    }
113499bfc35243bc810e59ef0c0f39bd79eb59030ab2Ecco Park
113599bfc35243bc810e59ef0c0f39bd79eb59030ab2Ecco Park    ALOGI("HCI Reset is done\n");
113699bfc35243bc810e59ef0c0f39bd79eb59030ab2Ecco Park    err = set_cntrlr_baud(fd, speed);
113799bfc35243bc810e59ef0c0f39bd79eb59030ab2Ecco Park    if (err < 0)
113899bfc35243bc810e59ef0c0f39bd79eb59030ab2Ecco Park        ALOGI("set_cntrlr_baud0:%d,%d\n", speed, err);
113999bfc35243bc810e59ef0c0f39bd79eb59030ab2Ecco Park
114099bfc35243bc810e59ef0c0f39bd79eb59030ab2Ecco Parkfailed:
114199bfc35243bc810e59ef0c0f39bd79eb59030ab2Ecco Park    if (err < 0) {
114299bfc35243bc810e59ef0c0f39bd79eb59030ab2Ecco Park        set_cntrlr_baud(fd, init_speed);
114399bfc35243bc810e59ef0c0f39bd79eb59030ab2Ecco Park        set_speed(fd, ti, init_speed);
114499bfc35243bc810e59ef0c0f39bd79eb59030ab2Ecco Park    }
114599bfc35243bc810e59ef0c0f39bd79eb59030ab2Ecco Park
114699bfc35243bc810e59ef0c0f39bd79eb59030ab2Ecco Park    return err;
114799bfc35243bc810e59ef0c0f39bd79eb59030ab2Ecco Park
114899bfc35243bc810e59ef0c0f39bd79eb59030ab2Ecco Park}
114999bfc35243bc810e59ef0c0f39bd79eb59030ab2Ecco Park#define BTPROTO_HCI 1
115099bfc35243bc810e59ef0c0f39bd79eb59030ab2Ecco Park
115199bfc35243bc810e59ef0c0f39bd79eb59030ab2Ecco Park/* Open HCI device.
115299bfc35243bc810e59ef0c0f39bd79eb59030ab2Ecco Park * Returns device descriptor (dd). */
115399bfc35243bc810e59ef0c0f39bd79eb59030ab2Ecco Parkint hci_open_dev(int dev_id)
115499bfc35243bc810e59ef0c0f39bd79eb59030ab2Ecco Park{
115599bfc35243bc810e59ef0c0f39bd79eb59030ab2Ecco Park    struct sockaddr_hci a;
115699bfc35243bc810e59ef0c0f39bd79eb59030ab2Ecco Park    int dd, err;
115799bfc35243bc810e59ef0c0f39bd79eb59030ab2Ecco Park
115899bfc35243bc810e59ef0c0f39bd79eb59030ab2Ecco Park    /* Create HCI socket */
115999bfc35243bc810e59ef0c0f39bd79eb59030ab2Ecco Park    dd = socket(AF_BLUETOOTH, SOCK_RAW, BTPROTO_HCI);
116099bfc35243bc810e59ef0c0f39bd79eb59030ab2Ecco Park    if (dd < 0)
116199bfc35243bc810e59ef0c0f39bd79eb59030ab2Ecco Park        return dd;
116299bfc35243bc810e59ef0c0f39bd79eb59030ab2Ecco Park
116399bfc35243bc810e59ef0c0f39bd79eb59030ab2Ecco Park    /* Bind socket to the HCI device */
116499bfc35243bc810e59ef0c0f39bd79eb59030ab2Ecco Park    memset(&a, 0, sizeof(a));
116599bfc35243bc810e59ef0c0f39bd79eb59030ab2Ecco Park    a.hci_family = AF_BLUETOOTH;
116699bfc35243bc810e59ef0c0f39bd79eb59030ab2Ecco Park    a.hci_dev = dev_id;
116799bfc35243bc810e59ef0c0f39bd79eb59030ab2Ecco Park    if (bind(dd, (struct sockaddr *) &a, sizeof(a)) < 0)
116899bfc35243bc810e59ef0c0f39bd79eb59030ab2Ecco Park        goto failed;
116999bfc35243bc810e59ef0c0f39bd79eb59030ab2Ecco Park
117099bfc35243bc810e59ef0c0f39bd79eb59030ab2Ecco Park    return dd;
117199bfc35243bc810e59ef0c0f39bd79eb59030ab2Ecco Park
117299bfc35243bc810e59ef0c0f39bd79eb59030ab2Ecco Parkfailed:
117399bfc35243bc810e59ef0c0f39bd79eb59030ab2Ecco Park    err = errno;
117499bfc35243bc810e59ef0c0f39bd79eb59030ab2Ecco Park    close(dd);
117599bfc35243bc810e59ef0c0f39bd79eb59030ab2Ecco Park    errno = err;
117699bfc35243bc810e59ef0c0f39bd79eb59030ab2Ecco Park
117799bfc35243bc810e59ef0c0f39bd79eb59030ab2Ecco Park    return -1;
117899bfc35243bc810e59ef0c0f39bd79eb59030ab2Ecco Park}
117999bfc35243bc810e59ef0c0f39bd79eb59030ab2Ecco Park
118099bfc35243bc810e59ef0c0f39bd79eb59030ab2Ecco Parkint hci_close_dev(int dd)
118199bfc35243bc810e59ef0c0f39bd79eb59030ab2Ecco Park{
118299bfc35243bc810e59ef0c0f39bd79eb59030ab2Ecco Park    return close(dd);
118399bfc35243bc810e59ef0c0f39bd79eb59030ab2Ecco Park}
118499bfc35243bc810e59ef0c0f39bd79eb59030ab2Ecco Park
118599bfc35243bc810e59ef0c0f39bd79eb59030ab2Ecco Park/* HCI functions that require open device
118699bfc35243bc810e59ef0c0f39bd79eb59030ab2Ecco Park * dd - Device descriptor returned by hci_open_dev. */
118799bfc35243bc810e59ef0c0f39bd79eb59030ab2Ecco Park
118899bfc35243bc810e59ef0c0f39bd79eb59030ab2Ecco Parkint hci_send_cmd(int dd, uint16_t ogf, uint16_t ocf, uint8_t plen, void *param)
118999bfc35243bc810e59ef0c0f39bd79eb59030ab2Ecco Park{
119099bfc35243bc810e59ef0c0f39bd79eb59030ab2Ecco Park    uint8_t type = HCI_COMMAND_PKT;
119199bfc35243bc810e59ef0c0f39bd79eb59030ab2Ecco Park    hci_command_hdr hc;
119299bfc35243bc810e59ef0c0f39bd79eb59030ab2Ecco Park    struct iovec iv[3];
119399bfc35243bc810e59ef0c0f39bd79eb59030ab2Ecco Park    int ivn;
119499bfc35243bc810e59ef0c0f39bd79eb59030ab2Ecco Park
119599bfc35243bc810e59ef0c0f39bd79eb59030ab2Ecco Park    hc.opcode = htobs(cmd_opcode_pack(ogf, ocf));
119699bfc35243bc810e59ef0c0f39bd79eb59030ab2Ecco Park    hc.plen= plen;
119799bfc35243bc810e59ef0c0f39bd79eb59030ab2Ecco Park
119899bfc35243bc810e59ef0c0f39bd79eb59030ab2Ecco Park    iv[0].iov_base = &type;
119999bfc35243bc810e59ef0c0f39bd79eb59030ab2Ecco Park    iv[0].iov_len  = 1;
120099bfc35243bc810e59ef0c0f39bd79eb59030ab2Ecco Park    iv[1].iov_base = &hc;
120199bfc35243bc810e59ef0c0f39bd79eb59030ab2Ecco Park    iv[1].iov_len  = HCI_COMMAND_HDR_SIZE;
120299bfc35243bc810e59ef0c0f39bd79eb59030ab2Ecco Park    ivn = 2;
120399bfc35243bc810e59ef0c0f39bd79eb59030ab2Ecco Park
120499bfc35243bc810e59ef0c0f39bd79eb59030ab2Ecco Park    if (plen) {
120599bfc35243bc810e59ef0c0f39bd79eb59030ab2Ecco Park        iv[2].iov_base = param;
120699bfc35243bc810e59ef0c0f39bd79eb59030ab2Ecco Park        iv[2].iov_len  = plen;
120799bfc35243bc810e59ef0c0f39bd79eb59030ab2Ecco Park        ivn = 3;
120899bfc35243bc810e59ef0c0f39bd79eb59030ab2Ecco Park    }
120999bfc35243bc810e59ef0c0f39bd79eb59030ab2Ecco Park
121099bfc35243bc810e59ef0c0f39bd79eb59030ab2Ecco Park    while (writev(dd, iv, ivn) < 0) {
121199bfc35243bc810e59ef0c0f39bd79eb59030ab2Ecco Park        if (errno == EAGAIN || errno == EINTR)
121299bfc35243bc810e59ef0c0f39bd79eb59030ab2Ecco Park            continue;
121399bfc35243bc810e59ef0c0f39bd79eb59030ab2Ecco Park        return -1;
121499bfc35243bc810e59ef0c0f39bd79eb59030ab2Ecco Park    }
121599bfc35243bc810e59ef0c0f39bd79eb59030ab2Ecco Park    return 0;
121699bfc35243bc810e59ef0c0f39bd79eb59030ab2Ecco Park}
121799bfc35243bc810e59ef0c0f39bd79eb59030ab2Ecco Park
121899bfc35243bc810e59ef0c0f39bd79eb59030ab2Ecco Park#define HCI_SLEEP_CMD_OCF     0x04
121999bfc35243bc810e59ef0c0f39bd79eb59030ab2Ecco Park#define TIOCSETD 0x5423
122099bfc35243bc810e59ef0c0f39bd79eb59030ab2Ecco Park#define HCIUARTSETFLAGS _IOW('U', 204, int)
122199bfc35243bc810e59ef0c0f39bd79eb59030ab2Ecco Park#define HCIUARTSETPROTO _IOW('U', 200, int)
122299bfc35243bc810e59ef0c0f39bd79eb59030ab2Ecco Park#define HCIUARTGETDEVICE _IOW('U', 202, int)
122399bfc35243bc810e59ef0c0f39bd79eb59030ab2Ecco Park/*
122499bfc35243bc810e59ef0c0f39bd79eb59030ab2Ecco Park * Atheros AR300x specific initialization post callback
122599bfc35243bc810e59ef0c0f39bd79eb59030ab2Ecco Park */
122699bfc35243bc810e59ef0c0f39bd79eb59030ab2Ecco Parkint ath3k_post(int fd, int pm)
122799bfc35243bc810e59ef0c0f39bd79eb59030ab2Ecco Park{
122899bfc35243bc810e59ef0c0f39bd79eb59030ab2Ecco Park    int dev_id, dd;
122999bfc35243bc810e59ef0c0f39bd79eb59030ab2Ecco Park    struct timespec tm = { 0, 50000};
123099bfc35243bc810e59ef0c0f39bd79eb59030ab2Ecco Park
123199bfc35243bc810e59ef0c0f39bd79eb59030ab2Ecco Park    sleep(1);
123299bfc35243bc810e59ef0c0f39bd79eb59030ab2Ecco Park
123399bfc35243bc810e59ef0c0f39bd79eb59030ab2Ecco Park    dev_id = ioctl(fd, HCIUARTGETDEVICE, 0);
123499bfc35243bc810e59ef0c0f39bd79eb59030ab2Ecco Park    if (dev_id < 0) {
123599bfc35243bc810e59ef0c0f39bd79eb59030ab2Ecco Park        perror("cannot get device id");
123699bfc35243bc810e59ef0c0f39bd79eb59030ab2Ecco Park        return dev_id;
123799bfc35243bc810e59ef0c0f39bd79eb59030ab2Ecco Park    }
123899bfc35243bc810e59ef0c0f39bd79eb59030ab2Ecco Park
123999bfc35243bc810e59ef0c0f39bd79eb59030ab2Ecco Park    dd = hci_open_dev(dev_id);
124099bfc35243bc810e59ef0c0f39bd79eb59030ab2Ecco Park    if (dd < 0) {
124199bfc35243bc810e59ef0c0f39bd79eb59030ab2Ecco Park        perror("HCI device open failed");
124299bfc35243bc810e59ef0c0f39bd79eb59030ab2Ecco Park        return dd;
124399bfc35243bc810e59ef0c0f39bd79eb59030ab2Ecco Park    }
124499bfc35243bc810e59ef0c0f39bd79eb59030ab2Ecco Park
124599bfc35243bc810e59ef0c0f39bd79eb59030ab2Ecco Park    if (ioctl(dd, HCIDEVUP, dev_id) < 0 && errno != EALREADY) {
124699bfc35243bc810e59ef0c0f39bd79eb59030ab2Ecco Park        perror("hci down:Power management Disabled");
124799bfc35243bc810e59ef0c0f39bd79eb59030ab2Ecco Park        hci_close_dev(dd);
124899bfc35243bc810e59ef0c0f39bd79eb59030ab2Ecco Park        return -1;
124999bfc35243bc810e59ef0c0f39bd79eb59030ab2Ecco Park    }
125099bfc35243bc810e59ef0c0f39bd79eb59030ab2Ecco Park
125199bfc35243bc810e59ef0c0f39bd79eb59030ab2Ecco Park    /* send vendor specific command with Sleep feature Enabled */
125299bfc35243bc810e59ef0c0f39bd79eb59030ab2Ecco Park    if (hci_send_cmd(dd, OGF_VENDOR_CMD, HCI_SLEEP_CMD_OCF, 1, &pm) < 0)
125399bfc35243bc810e59ef0c0f39bd79eb59030ab2Ecco Park        perror("PM command failed, power management Disabled");
125499bfc35243bc810e59ef0c0f39bd79eb59030ab2Ecco Park
125599bfc35243bc810e59ef0c0f39bd79eb59030ab2Ecco Park    nanosleep(&tm, NULL);
125699bfc35243bc810e59ef0c0f39bd79eb59030ab2Ecco Park    hci_close_dev(dd);
125799bfc35243bc810e59ef0c0f39bd79eb59030ab2Ecco Park
125899bfc35243bc810e59ef0c0f39bd79eb59030ab2Ecco Park    return 0;
125999bfc35243bc810e59ef0c0f39bd79eb59030ab2Ecco Park}
126099bfc35243bc810e59ef0c0f39bd79eb59030ab2Ecco Park
126199bfc35243bc810e59ef0c0f39bd79eb59030ab2Ecco Park
126299bfc35243bc810e59ef0c0f39bd79eb59030ab2Ecco Park
126399bfc35243bc810e59ef0c0f39bd79eb59030ab2Ecco Park#define FLOW_CTL    0x0001
126499bfc35243bc810e59ef0c0f39bd79eb59030ab2Ecco Park#define ENABLE_PM   1
126599bfc35243bc810e59ef0c0f39bd79eb59030ab2Ecco Park#define DISABLE_PM  0
126699bfc35243bc810e59ef0c0f39bd79eb59030ab2Ecco Park
126799bfc35243bc810e59ef0c0f39bd79eb59030ab2Ecco Park/* Initialize UART driver */
126899bfc35243bc810e59ef0c0f39bd79eb59030ab2Ecco Parkstatic int init_uart(char *dev, struct uart_t *u, int send_break, int raw)
126999bfc35243bc810e59ef0c0f39bd79eb59030ab2Ecco Park{
127099bfc35243bc810e59ef0c0f39bd79eb59030ab2Ecco Park    ALOGI(" %s ", __FUNCTION__);
127199bfc35243bc810e59ef0c0f39bd79eb59030ab2Ecco Park
127299bfc35243bc810e59ef0c0f39bd79eb59030ab2Ecco Park    struct termios ti;
127399bfc35243bc810e59ef0c0f39bd79eb59030ab2Ecco Park
127499bfc35243bc810e59ef0c0f39bd79eb59030ab2Ecco Park    int i, fd;
127599bfc35243bc810e59ef0c0f39bd79eb59030ab2Ecco Park    unsigned long flags = 0;
127699bfc35243bc810e59ef0c0f39bd79eb59030ab2Ecco Park
127799bfc35243bc810e59ef0c0f39bd79eb59030ab2Ecco Park    if (raw)
127899bfc35243bc810e59ef0c0f39bd79eb59030ab2Ecco Park        flags |= 1 << HCI_UART_RAW_DEVICE;
127999bfc35243bc810e59ef0c0f39bd79eb59030ab2Ecco Park
128099bfc35243bc810e59ef0c0f39bd79eb59030ab2Ecco Park
128199bfc35243bc810e59ef0c0f39bd79eb59030ab2Ecco Park    fd = open(dev, O_RDWR | O_NOCTTY);
128299bfc35243bc810e59ef0c0f39bd79eb59030ab2Ecco Park
128399bfc35243bc810e59ef0c0f39bd79eb59030ab2Ecco Park    if (fd < 0) {
128499bfc35243bc810e59ef0c0f39bd79eb59030ab2Ecco Park        ALOGI("Can't open serial port");
128599bfc35243bc810e59ef0c0f39bd79eb59030ab2Ecco Park        return -1;
128699bfc35243bc810e59ef0c0f39bd79eb59030ab2Ecco Park    }
128799bfc35243bc810e59ef0c0f39bd79eb59030ab2Ecco Park
128899bfc35243bc810e59ef0c0f39bd79eb59030ab2Ecco Park
128999bfc35243bc810e59ef0c0f39bd79eb59030ab2Ecco Park    tcflush(fd, TCIOFLUSH);
129099bfc35243bc810e59ef0c0f39bd79eb59030ab2Ecco Park
129199bfc35243bc810e59ef0c0f39bd79eb59030ab2Ecco Park    if (tcgetattr(fd, &ti) < 0) {
129299bfc35243bc810e59ef0c0f39bd79eb59030ab2Ecco Park        ALOGI("Can't get port settings: %d\n", errno);
129399bfc35243bc810e59ef0c0f39bd79eb59030ab2Ecco Park        return -1;
129499bfc35243bc810e59ef0c0f39bd79eb59030ab2Ecco Park    }
129599bfc35243bc810e59ef0c0f39bd79eb59030ab2Ecco Park
129699bfc35243bc810e59ef0c0f39bd79eb59030ab2Ecco Park    cfmakeraw(&ti);
129799bfc35243bc810e59ef0c0f39bd79eb59030ab2Ecco Park
129899bfc35243bc810e59ef0c0f39bd79eb59030ab2Ecco Park    ti.c_cflag |= CLOCAL;
129999bfc35243bc810e59ef0c0f39bd79eb59030ab2Ecco Park    if (u->flags & FLOW_CTL)
130099bfc35243bc810e59ef0c0f39bd79eb59030ab2Ecco Park        ti.c_cflag |= CRTSCTS;
130199bfc35243bc810e59ef0c0f39bd79eb59030ab2Ecco Park    else
130299bfc35243bc810e59ef0c0f39bd79eb59030ab2Ecco Park        ti.c_cflag &= ~CRTSCTS;
130399bfc35243bc810e59ef0c0f39bd79eb59030ab2Ecco Park
130499bfc35243bc810e59ef0c0f39bd79eb59030ab2Ecco Park    if (tcsetattr(fd, TCSANOW, &ti) < 0) {
130599bfc35243bc810e59ef0c0f39bd79eb59030ab2Ecco Park        ALOGI("Can't set port settings");
130699bfc35243bc810e59ef0c0f39bd79eb59030ab2Ecco Park        return -1;
130799bfc35243bc810e59ef0c0f39bd79eb59030ab2Ecco Park    }
130899bfc35243bc810e59ef0c0f39bd79eb59030ab2Ecco Park
130999bfc35243bc810e59ef0c0f39bd79eb59030ab2Ecco Park    if (set_speed(fd, &ti, u->init_speed) < 0) {
131099bfc35243bc810e59ef0c0f39bd79eb59030ab2Ecco Park        ALOGI("Can't set initial baud rate");
131199bfc35243bc810e59ef0c0f39bd79eb59030ab2Ecco Park        return -1;
131299bfc35243bc810e59ef0c0f39bd79eb59030ab2Ecco Park    }
131399bfc35243bc810e59ef0c0f39bd79eb59030ab2Ecco Park
131499bfc35243bc810e59ef0c0f39bd79eb59030ab2Ecco Park    tcflush(fd, TCIOFLUSH);
131599bfc35243bc810e59ef0c0f39bd79eb59030ab2Ecco Park
131699bfc35243bc810e59ef0c0f39bd79eb59030ab2Ecco Park    if (send_break) {
131799bfc35243bc810e59ef0c0f39bd79eb59030ab2Ecco Park        tcsendbreak(fd, 0);
131899bfc35243bc810e59ef0c0f39bd79eb59030ab2Ecco Park        usleep(500000);
131999bfc35243bc810e59ef0c0f39bd79eb59030ab2Ecco Park    }
132099bfc35243bc810e59ef0c0f39bd79eb59030ab2Ecco Park
132199bfc35243bc810e59ef0c0f39bd79eb59030ab2Ecco Park    ath3k_init(fd,u->speed,u->init_speed,u->bdaddr, &ti);
132299bfc35243bc810e59ef0c0f39bd79eb59030ab2Ecco Park
132399bfc35243bc810e59ef0c0f39bd79eb59030ab2Ecco Park    ALOGI("Device setup complete\n");
132499bfc35243bc810e59ef0c0f39bd79eb59030ab2Ecco Park
132599bfc35243bc810e59ef0c0f39bd79eb59030ab2Ecco Park
132699bfc35243bc810e59ef0c0f39bd79eb59030ab2Ecco Park    tcflush(fd, TCIOFLUSH);
132799bfc35243bc810e59ef0c0f39bd79eb59030ab2Ecco Park
132899bfc35243bc810e59ef0c0f39bd79eb59030ab2Ecco Park    // Set actual baudrate
132999bfc35243bc810e59ef0c0f39bd79eb59030ab2Ecco Park    /*
133099bfc35243bc810e59ef0c0f39bd79eb59030ab2Ecco Park    if (set_speed(fd, &ti, u->speed) < 0) {
133199bfc35243bc810e59ef0c0f39bd79eb59030ab2Ecco Park        perror("Can't set baud rate");
133299bfc35243bc810e59ef0c0f39bd79eb59030ab2Ecco Park        return -1;
133399bfc35243bc810e59ef0c0f39bd79eb59030ab2Ecco Park    }
133499bfc35243bc810e59ef0c0f39bd79eb59030ab2Ecco Park
133599bfc35243bc810e59ef0c0f39bd79eb59030ab2Ecco Park    i = N_HCI;
133699bfc35243bc810e59ef0c0f39bd79eb59030ab2Ecco Park    if (ioctl(fd, TIOCSETD, &i) < 0) {
133799bfc35243bc810e59ef0c0f39bd79eb59030ab2Ecco Park        perror("Can't set line discipline");
133899bfc35243bc810e59ef0c0f39bd79eb59030ab2Ecco Park        return -1;
133999bfc35243bc810e59ef0c0f39bd79eb59030ab2Ecco Park    }
134099bfc35243bc810e59ef0c0f39bd79eb59030ab2Ecco Park
134199bfc35243bc810e59ef0c0f39bd79eb59030ab2Ecco Park    if (flags && ioctl(fd, HCIUARTSETFLAGS, flags) < 0) {
134299bfc35243bc810e59ef0c0f39bd79eb59030ab2Ecco Park        perror("Can't set UART flags");
134399bfc35243bc810e59ef0c0f39bd79eb59030ab2Ecco Park        return -1;
134499bfc35243bc810e59ef0c0f39bd79eb59030ab2Ecco Park    }
134599bfc35243bc810e59ef0c0f39bd79eb59030ab2Ecco Park
134699bfc35243bc810e59ef0c0f39bd79eb59030ab2Ecco Park    if (ioctl(fd, HCIUARTSETPROTO, u->proto) < 0) {
134799bfc35243bc810e59ef0c0f39bd79eb59030ab2Ecco Park        perror("Can't set device");
134899bfc35243bc810e59ef0c0f39bd79eb59030ab2Ecco Park        return -1;
134999bfc35243bc810e59ef0c0f39bd79eb59030ab2Ecco Park    }
135099bfc35243bc810e59ef0c0f39bd79eb59030ab2Ecco Park
135199bfc35243bc810e59ef0c0f39bd79eb59030ab2Ecco Park#if !defined(SW_BOARD_HAVE_BLUETOOTH_RTK)
135299bfc35243bc810e59ef0c0f39bd79eb59030ab2Ecco Park    ath3k_post(fd, u->pm);
135399bfc35243bc810e59ef0c0f39bd79eb59030ab2Ecco Park#endif
135499bfc35243bc810e59ef0c0f39bd79eb59030ab2Ecco Park    */
135599bfc35243bc810e59ef0c0f39bd79eb59030ab2Ecco Park
135699bfc35243bc810e59ef0c0f39bd79eb59030ab2Ecco Park    return fd;
135799bfc35243bc810e59ef0c0f39bd79eb59030ab2Ecco Park}
135899bfc35243bc810e59ef0c0f39bd79eb59030ab2Ecco Park
135999bfc35243bc810e59ef0c0f39bd79eb59030ab2Ecco Park
136099bfc35243bc810e59ef0c0f39bd79eb59030ab2Ecco Parkint hw_config_ath3k(char *port_name)
136199bfc35243bc810e59ef0c0f39bd79eb59030ab2Ecco Park{
136299bfc35243bc810e59ef0c0f39bd79eb59030ab2Ecco Park    ALOGI(" %s ", __FUNCTION__);
136399bfc35243bc810e59ef0c0f39bd79eb59030ab2Ecco Park    PSCounter=0;
136499bfc35243bc810e59ef0c0f39bd79eb59030ab2Ecco Park    struct sigaction sa;
136599bfc35243bc810e59ef0c0f39bd79eb59030ab2Ecco Park    struct uart_t u ;
136699bfc35243bc810e59ef0c0f39bd79eb59030ab2Ecco Park    int n=0,send_break=0,raw=0;
136799bfc35243bc810e59ef0c0f39bd79eb59030ab2Ecco Park
136899bfc35243bc810e59ef0c0f39bd79eb59030ab2Ecco Park    memset(&u, 0, sizeof(u));
136999bfc35243bc810e59ef0c0f39bd79eb59030ab2Ecco Park    u.speed =3000000;
137099bfc35243bc810e59ef0c0f39bd79eb59030ab2Ecco Park    u.init_speed =115200;
137199bfc35243bc810e59ef0c0f39bd79eb59030ab2Ecco Park    u.flags |= FLOW_CTL;
137299bfc35243bc810e59ef0c0f39bd79eb59030ab2Ecco Park    u.pm = DISABLE_PM;
137399bfc35243bc810e59ef0c0f39bd79eb59030ab2Ecco Park
137499bfc35243bc810e59ef0c0f39bd79eb59030ab2Ecco Park    n = init_uart(port_name, &u, send_break, raw);
137599bfc35243bc810e59ef0c0f39bd79eb59030ab2Ecco Park    if (n < 0) {
137699bfc35243bc810e59ef0c0f39bd79eb59030ab2Ecco Park        ALOGI("Can't initialize device");
137799bfc35243bc810e59ef0c0f39bd79eb59030ab2Ecco Park    }
137899bfc35243bc810e59ef0c0f39bd79eb59030ab2Ecco Park
137999bfc35243bc810e59ef0c0f39bd79eb59030ab2Ecco Park    return n;
138099bfc35243bc810e59ef0c0f39bd79eb59030ab2Ecco Park}
138199bfc35243bc810e59ef0c0f39bd79eb59030ab2Ecco Park
138299bfc35243bc810e59ef0c0f39bd79eb59030ab2Ecco Parkvoid lpm_set_ar3k(uint8_t pio, uint8_t action, uint8_t polarity)
138399bfc35243bc810e59ef0c0f39bd79eb59030ab2Ecco Park{
138499bfc35243bc810e59ef0c0f39bd79eb59030ab2Ecco Park    int rc;
138599bfc35243bc810e59ef0c0f39bd79eb59030ab2Ecco Park    int fd = -1;
138699bfc35243bc810e59ef0c0f39bd79eb59030ab2Ecco Park    char buffer;
138799bfc35243bc810e59ef0c0f39bd79eb59030ab2Ecco Park
138899bfc35243bc810e59ef0c0f39bd79eb59030ab2Ecco Park    ALOGI("lpm mode: %d  action: %d", pio, action);
138999bfc35243bc810e59ef0c0f39bd79eb59030ab2Ecco Park
139099bfc35243bc810e59ef0c0f39bd79eb59030ab2Ecco Park    switch (pio)
139199bfc35243bc810e59ef0c0f39bd79eb59030ab2Ecco Park    {
139299bfc35243bc810e59ef0c0f39bd79eb59030ab2Ecco Park        case UPIO_LPM_MODE:
139399bfc35243bc810e59ef0c0f39bd79eb59030ab2Ecco Park            if (upio_state[UPIO_LPM_MODE] == action)
139499bfc35243bc810e59ef0c0f39bd79eb59030ab2Ecco Park            {
139599bfc35243bc810e59ef0c0f39bd79eb59030ab2Ecco Park                ALOGI("LPM is %s already", lpm_mode[action]);
139699bfc35243bc810e59ef0c0f39bd79eb59030ab2Ecco Park                return;
139799bfc35243bc810e59ef0c0f39bd79eb59030ab2Ecco Park            }
139899bfc35243bc810e59ef0c0f39bd79eb59030ab2Ecco Park
139999bfc35243bc810e59ef0c0f39bd79eb59030ab2Ecco Park            fd = open(VENDOR_LPM_PROC_NODE, O_WRONLY);
140099bfc35243bc810e59ef0c0f39bd79eb59030ab2Ecco Park
140199bfc35243bc810e59ef0c0f39bd79eb59030ab2Ecco Park            if (fd < 0)
140299bfc35243bc810e59ef0c0f39bd79eb59030ab2Ecco Park            {
140399bfc35243bc810e59ef0c0f39bd79eb59030ab2Ecco Park                ALOGE("upio_set : open(%s) for write failed: %s (%d)",
140499bfc35243bc810e59ef0c0f39bd79eb59030ab2Ecco Park                VENDOR_LPM_PROC_NODE, strerror(errno), errno);
140599bfc35243bc810e59ef0c0f39bd79eb59030ab2Ecco Park                return;
140699bfc35243bc810e59ef0c0f39bd79eb59030ab2Ecco Park            }
140799bfc35243bc810e59ef0c0f39bd79eb59030ab2Ecco Park
140899bfc35243bc810e59ef0c0f39bd79eb59030ab2Ecco Park            if (action == UPIO_ASSERT)
140999bfc35243bc810e59ef0c0f39bd79eb59030ab2Ecco Park            {
141099bfc35243bc810e59ef0c0f39bd79eb59030ab2Ecco Park                buffer = '1';
141199bfc35243bc810e59ef0c0f39bd79eb59030ab2Ecco Park            }
141299bfc35243bc810e59ef0c0f39bd79eb59030ab2Ecco Park            else
141399bfc35243bc810e59ef0c0f39bd79eb59030ab2Ecco Park            {
141499bfc35243bc810e59ef0c0f39bd79eb59030ab2Ecco Park                buffer = '0';
141599bfc35243bc810e59ef0c0f39bd79eb59030ab2Ecco Park            }
141699bfc35243bc810e59ef0c0f39bd79eb59030ab2Ecco Park
141799bfc35243bc810e59ef0c0f39bd79eb59030ab2Ecco Park            if (write(fd, &buffer, 1) < 0)
141899bfc35243bc810e59ef0c0f39bd79eb59030ab2Ecco Park            {
141999bfc35243bc810e59ef0c0f39bd79eb59030ab2Ecco Park                ALOGE("upio_set : write(%s) failed: %s (%d)",
142099bfc35243bc810e59ef0c0f39bd79eb59030ab2Ecco Park                VENDOR_LPM_PROC_NODE, strerror(errno),errno);
142199bfc35243bc810e59ef0c0f39bd79eb59030ab2Ecco Park            }
142299bfc35243bc810e59ef0c0f39bd79eb59030ab2Ecco Park            else
142399bfc35243bc810e59ef0c0f39bd79eb59030ab2Ecco Park            {
142499bfc35243bc810e59ef0c0f39bd79eb59030ab2Ecco Park                upio_state[UPIO_LPM_MODE] = action;
142599bfc35243bc810e59ef0c0f39bd79eb59030ab2Ecco Park                ALOGI("LPM is set to %s", lpm_mode[action]);
142699bfc35243bc810e59ef0c0f39bd79eb59030ab2Ecco Park            }
142799bfc35243bc810e59ef0c0f39bd79eb59030ab2Ecco Park
142899bfc35243bc810e59ef0c0f39bd79eb59030ab2Ecco Park            if (fd >= 0)
142999bfc35243bc810e59ef0c0f39bd79eb59030ab2Ecco Park                close(fd);
143099bfc35243bc810e59ef0c0f39bd79eb59030ab2Ecco Park
143199bfc35243bc810e59ef0c0f39bd79eb59030ab2Ecco Park            break;
143299bfc35243bc810e59ef0c0f39bd79eb59030ab2Ecco Park
143399bfc35243bc810e59ef0c0f39bd79eb59030ab2Ecco Park        case UPIO_BT_WAKE:
143499bfc35243bc810e59ef0c0f39bd79eb59030ab2Ecco Park            /* UPIO_DEASSERT should be allowed because in Rx case assert occur
143599bfc35243bc810e59ef0c0f39bd79eb59030ab2Ecco Park            * from the remote side where as deassert  will be initiated from Host
143699bfc35243bc810e59ef0c0f39bd79eb59030ab2Ecco Park            */
143799bfc35243bc810e59ef0c0f39bd79eb59030ab2Ecco Park            if ((action == UPIO_ASSERT) && (upio_state[UPIO_BT_WAKE] == action))
143899bfc35243bc810e59ef0c0f39bd79eb59030ab2Ecco Park            {
143999bfc35243bc810e59ef0c0f39bd79eb59030ab2Ecco Park                ALOGI("BT_WAKE is %s already", lpm_state[action]);
144099bfc35243bc810e59ef0c0f39bd79eb59030ab2Ecco Park
144199bfc35243bc810e59ef0c0f39bd79eb59030ab2Ecco Park                return;
144299bfc35243bc810e59ef0c0f39bd79eb59030ab2Ecco Park            }
144399bfc35243bc810e59ef0c0f39bd79eb59030ab2Ecco Park
144499bfc35243bc810e59ef0c0f39bd79eb59030ab2Ecco Park            if (action == UPIO_DEASSERT)
144599bfc35243bc810e59ef0c0f39bd79eb59030ab2Ecco Park                buffer = '0';
144699bfc35243bc810e59ef0c0f39bd79eb59030ab2Ecco Park            else
144799bfc35243bc810e59ef0c0f39bd79eb59030ab2Ecco Park                buffer = '1';
144899bfc35243bc810e59ef0c0f39bd79eb59030ab2Ecco Park
144999bfc35243bc810e59ef0c0f39bd79eb59030ab2Ecco Park            fd = open(VENDOR_BTWRITE_PROC_NODE, O_WRONLY);
145099bfc35243bc810e59ef0c0f39bd79eb59030ab2Ecco Park
145199bfc35243bc810e59ef0c0f39bd79eb59030ab2Ecco Park            if (fd < 0)
145299bfc35243bc810e59ef0c0f39bd79eb59030ab2Ecco Park            {
145399bfc35243bc810e59ef0c0f39bd79eb59030ab2Ecco Park                ALOGE("upio_set : open(%s) for write failed: %s (%d)",
145499bfc35243bc810e59ef0c0f39bd79eb59030ab2Ecco Park                VENDOR_BTWRITE_PROC_NODE, strerror(errno), errno);
145599bfc35243bc810e59ef0c0f39bd79eb59030ab2Ecco Park                return;
145699bfc35243bc810e59ef0c0f39bd79eb59030ab2Ecco Park            }
145799bfc35243bc810e59ef0c0f39bd79eb59030ab2Ecco Park
145899bfc35243bc810e59ef0c0f39bd79eb59030ab2Ecco Park            if (write(fd, &buffer, 1) < 0)
145999bfc35243bc810e59ef0c0f39bd79eb59030ab2Ecco Park            {
146099bfc35243bc810e59ef0c0f39bd79eb59030ab2Ecco Park                ALOGE("upio_set : write(%s) failed: %s (%d)",
146199bfc35243bc810e59ef0c0f39bd79eb59030ab2Ecco Park                VENDOR_BTWRITE_PROC_NODE, strerror(errno),errno);
146299bfc35243bc810e59ef0c0f39bd79eb59030ab2Ecco Park            }
146399bfc35243bc810e59ef0c0f39bd79eb59030ab2Ecco Park            else
146499bfc35243bc810e59ef0c0f39bd79eb59030ab2Ecco Park            {
146599bfc35243bc810e59ef0c0f39bd79eb59030ab2Ecco Park                upio_state[UPIO_BT_WAKE] = action;
146699bfc35243bc810e59ef0c0f39bd79eb59030ab2Ecco Park                ALOGI("BT_WAKE is set to %s", lpm_state[action]);
146799bfc35243bc810e59ef0c0f39bd79eb59030ab2Ecco Park            }
146899bfc35243bc810e59ef0c0f39bd79eb59030ab2Ecco Park
146999bfc35243bc810e59ef0c0f39bd79eb59030ab2Ecco Park            ALOGI("proc btwrite assertion");
147099bfc35243bc810e59ef0c0f39bd79eb59030ab2Ecco Park
147199bfc35243bc810e59ef0c0f39bd79eb59030ab2Ecco Park            if (fd >= 0)
147299bfc35243bc810e59ef0c0f39bd79eb59030ab2Ecco Park                close(fd);
147399bfc35243bc810e59ef0c0f39bd79eb59030ab2Ecco Park
147499bfc35243bc810e59ef0c0f39bd79eb59030ab2Ecco Park            break;
147599bfc35243bc810e59ef0c0f39bd79eb59030ab2Ecco Park
147699bfc35243bc810e59ef0c0f39bd79eb59030ab2Ecco Park        case UPIO_HOST_WAKE:
147799bfc35243bc810e59ef0c0f39bd79eb59030ab2Ecco Park            ALOGI("upio_set: UPIO_HOST_WAKE");
147899bfc35243bc810e59ef0c0f39bd79eb59030ab2Ecco Park            break;
147999bfc35243bc810e59ef0c0f39bd79eb59030ab2Ecco Park    }
148099bfc35243bc810e59ef0c0f39bd79eb59030ab2Ecco Park
148199bfc35243bc810e59ef0c0f39bd79eb59030ab2Ecco Park}
1482