10ebd0bab066cd86d7a19f4646e0686dae885004eThierry Strudel/*
20ebd0bab066cd86d7a19f4646e0686dae885004eThierry Strudel *
30ebd0bab066cd86d7a19f4646e0686dae885004eThierry Strudel *  Copyright (c) 2013, The Linux Foundation. All rights reserved.
40ebd0bab066cd86d7a19f4646e0686dae885004eThierry Strudel *  Not a Contribution.
50ebd0bab066cd86d7a19f4646e0686dae885004eThierry Strudel *
60ebd0bab066cd86d7a19f4646e0686dae885004eThierry Strudel *  Copyright 2012 The Android Open Source Project
70ebd0bab066cd86d7a19f4646e0686dae885004eThierry Strudel *
80ebd0bab066cd86d7a19f4646e0686dae885004eThierry Strudel *  Licensed under the Apache License, Version 2.0 (the "License"); you
90ebd0bab066cd86d7a19f4646e0686dae885004eThierry Strudel *  may not use this file except in compliance with the License. You may
100ebd0bab066cd86d7a19f4646e0686dae885004eThierry Strudel *  obtain a copy of the License at
110ebd0bab066cd86d7a19f4646e0686dae885004eThierry Strudel *
120ebd0bab066cd86d7a19f4646e0686dae885004eThierry Strudel *  http://www.apache.org/licenses/LICENSE-2.0
130ebd0bab066cd86d7a19f4646e0686dae885004eThierry Strudel *
140ebd0bab066cd86d7a19f4646e0686dae885004eThierry Strudel *  Unless required by applicable law or agreed to in writing, software
150ebd0bab066cd86d7a19f4646e0686dae885004eThierry Strudel *  distributed under the License is distributed on an "AS IS" BASIS,
160ebd0bab066cd86d7a19f4646e0686dae885004eThierry Strudel *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
170ebd0bab066cd86d7a19f4646e0686dae885004eThierry Strudel *  implied. See the License for the specific language governing
180ebd0bab066cd86d7a19f4646e0686dae885004eThierry Strudel *  permissions and limitations under the License.
190ebd0bab066cd86d7a19f4646e0686dae885004eThierry Strudel *
200ebd0bab066cd86d7a19f4646e0686dae885004eThierry Strudel */
210ebd0bab066cd86d7a19f4646e0686dae885004eThierry Strudel
220ebd0bab066cd86d7a19f4646e0686dae885004eThierry Strudel/******************************************************************************
230ebd0bab066cd86d7a19f4646e0686dae885004eThierry Strudel *
240ebd0bab066cd86d7a19f4646e0686dae885004eThierry Strudel *  Filename:      hw_ar3k.c
250ebd0bab066cd86d7a19f4646e0686dae885004eThierry Strudel *
260ebd0bab066cd86d7a19f4646e0686dae885004eThierry Strudel *  Description:   Contains controller-specific functions, like
270ebd0bab066cd86d7a19f4646e0686dae885004eThierry Strudel *                      firmware patch download
280ebd0bab066cd86d7a19f4646e0686dae885004eThierry Strudel *                      low power mode operations
290ebd0bab066cd86d7a19f4646e0686dae885004eThierry Strudel *
300ebd0bab066cd86d7a19f4646e0686dae885004eThierry Strudel ******************************************************************************/
310ebd0bab066cd86d7a19f4646e0686dae885004eThierry Strudel#ifdef __cplusplus
320ebd0bab066cd86d7a19f4646e0686dae885004eThierry Strudelextern "C" {
330ebd0bab066cd86d7a19f4646e0686dae885004eThierry Strudel#endif
340ebd0bab066cd86d7a19f4646e0686dae885004eThierry Strudel
350ebd0bab066cd86d7a19f4646e0686dae885004eThierry Strudel#define LOG_TAG "bt_vendor"
360ebd0bab066cd86d7a19f4646e0686dae885004eThierry Strudel
37abb4fd870fa1a3dd91a71f6e0d33d6aaa44079c1Jiyong Park#include "bt_hci_bdroid.h"
38abb4fd870fa1a3dd91a71f6e0d33d6aaa44079c1Jiyong Park#include "bt_vendor_qcom.h"
39abb4fd870fa1a3dd91a71f6e0d33d6aaa44079c1Jiyong Park#include "bt_vendor_qcom.h"
40abb4fd870fa1a3dd91a71f6e0d33d6aaa44079c1Jiyong Park#include "hci_uart.h"
41abb4fd870fa1a3dd91a71f6e0d33d6aaa44079c1Jiyong Park#include "hw_ar3k.h"
42abb4fd870fa1a3dd91a71f6e0d33d6aaa44079c1Jiyong Park
43abb4fd870fa1a3dd91a71f6e0d33d6aaa44079c1Jiyong Park#include <ctype.h>
44abb4fd870fa1a3dd91a71f6e0d33d6aaa44079c1Jiyong Park#include <dirent.h>
450ebd0bab066cd86d7a19f4646e0686dae885004eThierry Strudel#include <errno.h>
460ebd0bab066cd86d7a19f4646e0686dae885004eThierry Strudel#include <fcntl.h>
47abb4fd870fa1a3dd91a71f6e0d33d6aaa44079c1Jiyong Park#include <signal.h>
480ebd0bab066cd86d7a19f4646e0686dae885004eThierry Strudel#include <stdlib.h>
490ebd0bab066cd86d7a19f4646e0686dae885004eThierry Strudel#include <string.h>
50abb4fd870fa1a3dd91a71f6e0d33d6aaa44079c1Jiyong Park#include <sys/socket.h>
51abb4fd870fa1a3dd91a71f6e0d33d6aaa44079c1Jiyong Park#include <sys/stat.h>
52abb4fd870fa1a3dd91a71f6e0d33d6aaa44079c1Jiyong Park#include <sys/types.h>
53abb4fd870fa1a3dd91a71f6e0d33d6aaa44079c1Jiyong Park#include <sys/uio.h>
54abb4fd870fa1a3dd91a71f6e0d33d6aaa44079c1Jiyong Park#include <termios.h>
55abb4fd870fa1a3dd91a71f6e0d33d6aaa44079c1Jiyong Park#include <time.h>
56abb4fd870fa1a3dd91a71f6e0d33d6aaa44079c1Jiyong Park#include <unistd.h>
570ebd0bab066cd86d7a19f4646e0686dae885004eThierry Strudel
58abb4fd870fa1a3dd91a71f6e0d33d6aaa44079c1Jiyong Park#include <cutils/properties.h>
59abb4fd870fa1a3dd91a71f6e0d33d6aaa44079c1Jiyong Park#include <utils/Log.h>
600ebd0bab066cd86d7a19f4646e0686dae885004eThierry Strudel
610ebd0bab066cd86d7a19f4646e0686dae885004eThierry Strudel/******************************************************************************
620ebd0bab066cd86d7a19f4646e0686dae885004eThierry Strudel**  Variables
630ebd0bab066cd86d7a19f4646e0686dae885004eThierry Strudel******************************************************************************/
640ebd0bab066cd86d7a19f4646e0686dae885004eThierry Strudelint cbstat = 0;
650ebd0bab066cd86d7a19f4646e0686dae885004eThierry Strudel#define PATCH_LOC_STRING_LEN   8
660ebd0bab066cd86d7a19f4646e0686dae885004eThierry Strudelchar ARbyte[3];
670ebd0bab066cd86d7a19f4646e0686dae885004eThierry Strudelchar ARptr[MAX_PATCH_CMD + 1];
680ebd0bab066cd86d7a19f4646e0686dae885004eThierry Strudelint byte_cnt;
690ebd0bab066cd86d7a19f4646e0686dae885004eThierry Strudelint patch_count = 0;
700ebd0bab066cd86d7a19f4646e0686dae885004eThierry Strudelchar patch_loc[PATCH_LOC_STRING_LEN + 1];
710ebd0bab066cd86d7a19f4646e0686dae885004eThierry Strudelint PSCounter=0;
720ebd0bab066cd86d7a19f4646e0686dae885004eThierry Strudel
730ebd0bab066cd86d7a19f4646e0686dae885004eThierry Strudeluint32_t dev_type = 0;
740ebd0bab066cd86d7a19f4646e0686dae885004eThierry Strudeluint32_t rom_version = 0;
750ebd0bab066cd86d7a19f4646e0686dae885004eThierry Strudeluint32_t build_version = 0;
760ebd0bab066cd86d7a19f4646e0686dae885004eThierry Strudel
770ebd0bab066cd86d7a19f4646e0686dae885004eThierry Strudelchar patch_file[PATH_MAX];
780ebd0bab066cd86d7a19f4646e0686dae885004eThierry Strudelchar ps_file[PATH_MAX];
790ebd0bab066cd86d7a19f4646e0686dae885004eThierry StrudelFILE *stream;
800ebd0bab066cd86d7a19f4646e0686dae885004eThierry Strudelint tag_count=0;
810ebd0bab066cd86d7a19f4646e0686dae885004eThierry Strudel
820ebd0bab066cd86d7a19f4646e0686dae885004eThierry Strudel/* for friendly debugging outpout string */
830ebd0bab066cd86d7a19f4646e0686dae885004eThierry Strudelstatic char *lpm_mode[] = {
840ebd0bab066cd86d7a19f4646e0686dae885004eThierry Strudel    "UNKNOWN",
850ebd0bab066cd86d7a19f4646e0686dae885004eThierry Strudel    "disabled",
860ebd0bab066cd86d7a19f4646e0686dae885004eThierry Strudel    "enabled"
870ebd0bab066cd86d7a19f4646e0686dae885004eThierry Strudel};
880ebd0bab066cd86d7a19f4646e0686dae885004eThierry Strudel
890ebd0bab066cd86d7a19f4646e0686dae885004eThierry Strudelstatic char *lpm_state[] = {
900ebd0bab066cd86d7a19f4646e0686dae885004eThierry Strudel    "UNKNOWN",
910ebd0bab066cd86d7a19f4646e0686dae885004eThierry Strudel    "de-asserted",
920ebd0bab066cd86d7a19f4646e0686dae885004eThierry Strudel    "asserted"
930ebd0bab066cd86d7a19f4646e0686dae885004eThierry Strudel};
940ebd0bab066cd86d7a19f4646e0686dae885004eThierry Strudel
950ebd0bab066cd86d7a19f4646e0686dae885004eThierry Strudelstatic uint8_t upio_state[UPIO_MAX_COUNT];
960ebd0bab066cd86d7a19f4646e0686dae885004eThierry Strudelstruct ps_cfg_entry ps_list[MAX_TAGS];
970ebd0bab066cd86d7a19f4646e0686dae885004eThierry Strudel
980ebd0bab066cd86d7a19f4646e0686dae885004eThierry Strudel#define PS_EVENT_LEN 100
990ebd0bab066cd86d7a19f4646e0686dae885004eThierry Strudel
1000ebd0bab066cd86d7a19f4646e0686dae885004eThierry Strudel#ifdef __cplusplus
1010ebd0bab066cd86d7a19f4646e0686dae885004eThierry Strudel}
1020ebd0bab066cd86d7a19f4646e0686dae885004eThierry Strudel#endif
1030ebd0bab066cd86d7a19f4646e0686dae885004eThierry Strudel
1040ebd0bab066cd86d7a19f4646e0686dae885004eThierry Strudel#define RESERVED(p)  if(p) ALOGI( "%s: reserved param", __FUNCTION__);
1050ebd0bab066cd86d7a19f4646e0686dae885004eThierry Strudel
1060ebd0bab066cd86d7a19f4646e0686dae885004eThierry Strudel/*****************************************************************************
1070ebd0bab066cd86d7a19f4646e0686dae885004eThierry Strudel**   Functions
1080ebd0bab066cd86d7a19f4646e0686dae885004eThierry Strudel*****************************************************************************/
1090ebd0bab066cd86d7a19f4646e0686dae885004eThierry Strudel
1100ebd0bab066cd86d7a19f4646e0686dae885004eThierry Strudelint is_bt_soc_ath() {
1110ebd0bab066cd86d7a19f4646e0686dae885004eThierry Strudel    int ret = 0;
1120ebd0bab066cd86d7a19f4646e0686dae885004eThierry Strudel    char bt_soc_type[PROPERTY_VALUE_MAX];
1130ebd0bab066cd86d7a19f4646e0686dae885004eThierry Strudel    ret = property_get("qcom.bluetooth.soc", bt_soc_type, NULL);
1140ebd0bab066cd86d7a19f4646e0686dae885004eThierry Strudel    if (ret != 0) {
1150ebd0bab066cd86d7a19f4646e0686dae885004eThierry Strudel        ALOGI("qcom.bluetooth.soc set to %s\n", bt_soc_type);
1160ebd0bab066cd86d7a19f4646e0686dae885004eThierry Strudel        if (!strncasecmp(bt_soc_type, "ath3k", sizeof("ath3k")))
1170ebd0bab066cd86d7a19f4646e0686dae885004eThierry Strudel            return 1;
1180ebd0bab066cd86d7a19f4646e0686dae885004eThierry Strudel    } else {
1190ebd0bab066cd86d7a19f4646e0686dae885004eThierry Strudel        ALOGI("qcom.bluetooth.soc not set, so using default.\n");
1200ebd0bab066cd86d7a19f4646e0686dae885004eThierry Strudel    }
1210ebd0bab066cd86d7a19f4646e0686dae885004eThierry Strudel
1220ebd0bab066cd86d7a19f4646e0686dae885004eThierry Strudel    return 0;
1230ebd0bab066cd86d7a19f4646e0686dae885004eThierry Strudel}
1240ebd0bab066cd86d7a19f4646e0686dae885004eThierry Strudel
1250ebd0bab066cd86d7a19f4646e0686dae885004eThierry Strudel/*
1260ebd0bab066cd86d7a19f4646e0686dae885004eThierry Strudel * Send HCI command and wait for command complete event.
1270ebd0bab066cd86d7a19f4646e0686dae885004eThierry Strudel * The event buffer has to be freed by the caller.
1280ebd0bab066cd86d7a19f4646e0686dae885004eThierry Strudel */
1290ebd0bab066cd86d7a19f4646e0686dae885004eThierry Strudel
1300ebd0bab066cd86d7a19f4646e0686dae885004eThierry Strudelstatic int send_hci_cmd_sync(int dev, uint8_t *cmd, int len, uint8_t **event)
1310ebd0bab066cd86d7a19f4646e0686dae885004eThierry Strudel{
1320ebd0bab066cd86d7a19f4646e0686dae885004eThierry Strudel    int err;
1330ebd0bab066cd86d7a19f4646e0686dae885004eThierry Strudel    uint8_t *hci_event;
1340ebd0bab066cd86d7a19f4646e0686dae885004eThierry Strudel    uint8_t pkt_type = HCI_COMMAND_PKT;
1350ebd0bab066cd86d7a19f4646e0686dae885004eThierry Strudel
1360ebd0bab066cd86d7a19f4646e0686dae885004eThierry Strudel    if (len == 0)
1370ebd0bab066cd86d7a19f4646e0686dae885004eThierry Strudel    return len;
1380ebd0bab066cd86d7a19f4646e0686dae885004eThierry Strudel
1390ebd0bab066cd86d7a19f4646e0686dae885004eThierry Strudel    if (write(dev, &pkt_type, 1) != 1)
1400ebd0bab066cd86d7a19f4646e0686dae885004eThierry Strudel        return -EILSEQ;
1410ebd0bab066cd86d7a19f4646e0686dae885004eThierry Strudel    if (write(dev, (unsigned char *)cmd, len) != len)
1420ebd0bab066cd86d7a19f4646e0686dae885004eThierry Strudel        return -EILSEQ;
1430ebd0bab066cd86d7a19f4646e0686dae885004eThierry Strudel
1440ebd0bab066cd86d7a19f4646e0686dae885004eThierry Strudel    hci_event = (uint8_t *)malloc(PS_EVENT_LEN);
1450ebd0bab066cd86d7a19f4646e0686dae885004eThierry Strudel    if (!hci_event)
1460ebd0bab066cd86d7a19f4646e0686dae885004eThierry Strudel        return -ENOMEM;
1470ebd0bab066cd86d7a19f4646e0686dae885004eThierry Strudel
1480ebd0bab066cd86d7a19f4646e0686dae885004eThierry Strudel    err = read_hci_event(dev, (unsigned char *)hci_event, PS_EVENT_LEN);
1490ebd0bab066cd86d7a19f4646e0686dae885004eThierry Strudel    if (err > 0) {
1500ebd0bab066cd86d7a19f4646e0686dae885004eThierry Strudel        *event = hci_event;
1510ebd0bab066cd86d7a19f4646e0686dae885004eThierry Strudel    } else {
1520ebd0bab066cd86d7a19f4646e0686dae885004eThierry Strudel        free(hci_event);
1530ebd0bab066cd86d7a19f4646e0686dae885004eThierry Strudel        return -EILSEQ;
1540ebd0bab066cd86d7a19f4646e0686dae885004eThierry Strudel    }
1550ebd0bab066cd86d7a19f4646e0686dae885004eThierry Strudel
1560ebd0bab066cd86d7a19f4646e0686dae885004eThierry Strudel    return len;
1570ebd0bab066cd86d7a19f4646e0686dae885004eThierry Strudel}
1580ebd0bab066cd86d7a19f4646e0686dae885004eThierry Strudel
1590ebd0bab066cd86d7a19f4646e0686dae885004eThierry Strudelstatic void convert_bdaddr(char *str_bdaddr, char *bdaddr)
1600ebd0bab066cd86d7a19f4646e0686dae885004eThierry Strudel{
1610ebd0bab066cd86d7a19f4646e0686dae885004eThierry Strudel    char bdbyte[3];
1620ebd0bab066cd86d7a19f4646e0686dae885004eThierry Strudel    char *str_byte = str_bdaddr;
1630ebd0bab066cd86d7a19f4646e0686dae885004eThierry Strudel    int i, j;
1640ebd0bab066cd86d7a19f4646e0686dae885004eThierry Strudel    int colon_present = 0;
1650ebd0bab066cd86d7a19f4646e0686dae885004eThierry Strudel
1660ebd0bab066cd86d7a19f4646e0686dae885004eThierry Strudel    if (strstr(str_bdaddr, ":"))
1670ebd0bab066cd86d7a19f4646e0686dae885004eThierry Strudel        colon_present = 1;
1680ebd0bab066cd86d7a19f4646e0686dae885004eThierry Strudel
1690ebd0bab066cd86d7a19f4646e0686dae885004eThierry Strudel    bdbyte[2] = '\0';
1700ebd0bab066cd86d7a19f4646e0686dae885004eThierry Strudel
1710ebd0bab066cd86d7a19f4646e0686dae885004eThierry Strudel    /* Reverse the BDADDR to LSB first */
1720ebd0bab066cd86d7a19f4646e0686dae885004eThierry Strudel    for (i = 0, j = 5; i < 6; i++, j--) {
1730ebd0bab066cd86d7a19f4646e0686dae885004eThierry Strudel        bdbyte[0] = str_byte[0];
1740ebd0bab066cd86d7a19f4646e0686dae885004eThierry Strudel        bdbyte[1] = str_byte[1];
1750ebd0bab066cd86d7a19f4646e0686dae885004eThierry Strudel        bdaddr[j] = strtol(bdbyte, NULL, 16);
1760ebd0bab066cd86d7a19f4646e0686dae885004eThierry Strudel
1770ebd0bab066cd86d7a19f4646e0686dae885004eThierry Strudel        if (colon_present == 1)
1780ebd0bab066cd86d7a19f4646e0686dae885004eThierry Strudel            str_byte += 3;
1790ebd0bab066cd86d7a19f4646e0686dae885004eThierry Strudel        else
1800ebd0bab066cd86d7a19f4646e0686dae885004eThierry Strudel            str_byte += 2;
1810ebd0bab066cd86d7a19f4646e0686dae885004eThierry Strudel    }
1820ebd0bab066cd86d7a19f4646e0686dae885004eThierry Strudel}
1830ebd0bab066cd86d7a19f4646e0686dae885004eThierry Strudel
1840ebd0bab066cd86d7a19f4646e0686dae885004eThierry Strudelstatic int uart_speed(int s)
1850ebd0bab066cd86d7a19f4646e0686dae885004eThierry Strudel{
1860ebd0bab066cd86d7a19f4646e0686dae885004eThierry Strudel    switch (s) {
1870ebd0bab066cd86d7a19f4646e0686dae885004eThierry Strudel        case 9600:
1880ebd0bab066cd86d7a19f4646e0686dae885004eThierry Strudel            return B9600;
1890ebd0bab066cd86d7a19f4646e0686dae885004eThierry Strudel        case 19200:
1900ebd0bab066cd86d7a19f4646e0686dae885004eThierry Strudel            return B19200;
1910ebd0bab066cd86d7a19f4646e0686dae885004eThierry Strudel        case 38400:
1920ebd0bab066cd86d7a19f4646e0686dae885004eThierry Strudel            return B38400;
1930ebd0bab066cd86d7a19f4646e0686dae885004eThierry Strudel        case 57600:
1940ebd0bab066cd86d7a19f4646e0686dae885004eThierry Strudel            return B57600;
1950ebd0bab066cd86d7a19f4646e0686dae885004eThierry Strudel        case 115200:
1960ebd0bab066cd86d7a19f4646e0686dae885004eThierry Strudel            return B115200;
1970ebd0bab066cd86d7a19f4646e0686dae885004eThierry Strudel        case 230400:
1980ebd0bab066cd86d7a19f4646e0686dae885004eThierry Strudel            return B230400;
1990ebd0bab066cd86d7a19f4646e0686dae885004eThierry Strudel        case 460800:
2000ebd0bab066cd86d7a19f4646e0686dae885004eThierry Strudel            return B460800;
2010ebd0bab066cd86d7a19f4646e0686dae885004eThierry Strudel        case 500000:
2020ebd0bab066cd86d7a19f4646e0686dae885004eThierry Strudel            return B500000;
2030ebd0bab066cd86d7a19f4646e0686dae885004eThierry Strudel        case 576000:
2040ebd0bab066cd86d7a19f4646e0686dae885004eThierry Strudel            return B576000;
2050ebd0bab066cd86d7a19f4646e0686dae885004eThierry Strudel        case 921600:
2060ebd0bab066cd86d7a19f4646e0686dae885004eThierry Strudel            return B921600;
2070ebd0bab066cd86d7a19f4646e0686dae885004eThierry Strudel        case 1000000:
2080ebd0bab066cd86d7a19f4646e0686dae885004eThierry Strudel            return B1000000;
2090ebd0bab066cd86d7a19f4646e0686dae885004eThierry Strudel        case 1152000:
2100ebd0bab066cd86d7a19f4646e0686dae885004eThierry Strudel            return B1152000;
2110ebd0bab066cd86d7a19f4646e0686dae885004eThierry Strudel        case 1500000:
2120ebd0bab066cd86d7a19f4646e0686dae885004eThierry Strudel            return B1500000;
2130ebd0bab066cd86d7a19f4646e0686dae885004eThierry Strudel        case 2000000:
2140ebd0bab066cd86d7a19f4646e0686dae885004eThierry Strudel            return B2000000;
2150ebd0bab066cd86d7a19f4646e0686dae885004eThierry Strudel#ifdef B2500000
2160ebd0bab066cd86d7a19f4646e0686dae885004eThierry Strudel        case 2500000:
2170ebd0bab066cd86d7a19f4646e0686dae885004eThierry Strudel            return B2500000;
2180ebd0bab066cd86d7a19f4646e0686dae885004eThierry Strudel#endif
2190ebd0bab066cd86d7a19f4646e0686dae885004eThierry Strudel#ifdef B3000000
2200ebd0bab066cd86d7a19f4646e0686dae885004eThierry Strudel        case 3000000:
2210ebd0bab066cd86d7a19f4646e0686dae885004eThierry Strudel            return B3000000;
2220ebd0bab066cd86d7a19f4646e0686dae885004eThierry Strudel#endif
2230ebd0bab066cd86d7a19f4646e0686dae885004eThierry Strudel#ifdef B3500000
2240ebd0bab066cd86d7a19f4646e0686dae885004eThierry Strudel        case 3500000:
2250ebd0bab066cd86d7a19f4646e0686dae885004eThierry Strudel            return B3500000;
2260ebd0bab066cd86d7a19f4646e0686dae885004eThierry Strudel#endif
2270ebd0bab066cd86d7a19f4646e0686dae885004eThierry Strudel#ifdef B4000000
2280ebd0bab066cd86d7a19f4646e0686dae885004eThierry Strudel        case 4000000:
2290ebd0bab066cd86d7a19f4646e0686dae885004eThierry Strudel            return B4000000;
2300ebd0bab066cd86d7a19f4646e0686dae885004eThierry Strudel#endif
2310ebd0bab066cd86d7a19f4646e0686dae885004eThierry Strudel        default:
2320ebd0bab066cd86d7a19f4646e0686dae885004eThierry Strudel            return B57600;
2330ebd0bab066cd86d7a19f4646e0686dae885004eThierry Strudel    }
2340ebd0bab066cd86d7a19f4646e0686dae885004eThierry Strudel}
2350ebd0bab066cd86d7a19f4646e0686dae885004eThierry Strudel
2360ebd0bab066cd86d7a19f4646e0686dae885004eThierry Strudelint set_speed(int fd, struct termios *ti, int speed)
2370ebd0bab066cd86d7a19f4646e0686dae885004eThierry Strudel{
2380ebd0bab066cd86d7a19f4646e0686dae885004eThierry Strudel    if (cfsetospeed(ti, uart_speed(speed)) < 0)
2390ebd0bab066cd86d7a19f4646e0686dae885004eThierry Strudel        return -errno;
2400ebd0bab066cd86d7a19f4646e0686dae885004eThierry Strudel
2410ebd0bab066cd86d7a19f4646e0686dae885004eThierry Strudel    if (cfsetispeed(ti, uart_speed(speed)) < 0)
2420ebd0bab066cd86d7a19f4646e0686dae885004eThierry Strudel        return -errno;
2430ebd0bab066cd86d7a19f4646e0686dae885004eThierry Strudel
2440ebd0bab066cd86d7a19f4646e0686dae885004eThierry Strudel    if (tcsetattr(fd, TCSANOW, ti) < 0)
2450ebd0bab066cd86d7a19f4646e0686dae885004eThierry Strudel        return -errno;
2460ebd0bab066cd86d7a19f4646e0686dae885004eThierry Strudel
2470ebd0bab066cd86d7a19f4646e0686dae885004eThierry Strudel    return 0;
2480ebd0bab066cd86d7a19f4646e0686dae885004eThierry Strudel}
2490ebd0bab066cd86d7a19f4646e0686dae885004eThierry Strudel
2500ebd0bab066cd86d7a19f4646e0686dae885004eThierry Strudelstatic void load_hci_ps_hdr(uint8_t *cmd, uint8_t ps_op, int len, int index)
2510ebd0bab066cd86d7a19f4646e0686dae885004eThierry Strudel{
2520ebd0bab066cd86d7a19f4646e0686dae885004eThierry Strudel    hci_command_hdr *ch = (void *)cmd;
2530ebd0bab066cd86d7a19f4646e0686dae885004eThierry Strudel
2540ebd0bab066cd86d7a19f4646e0686dae885004eThierry Strudel    ch->opcode = htobs(cmd_opcode_pack(HCI_VENDOR_CMD_OGF,
2550ebd0bab066cd86d7a19f4646e0686dae885004eThierry Strudel        HCI_PS_CMD_OCF));
2560ebd0bab066cd86d7a19f4646e0686dae885004eThierry Strudel    ch->plen = len + PS_HDR_LEN;
2570ebd0bab066cd86d7a19f4646e0686dae885004eThierry Strudel    cmd += HCI_COMMAND_HDR_SIZE;
2580ebd0bab066cd86d7a19f4646e0686dae885004eThierry Strudel
2590ebd0bab066cd86d7a19f4646e0686dae885004eThierry Strudel    cmd[0] = ps_op;
2600ebd0bab066cd86d7a19f4646e0686dae885004eThierry Strudel    cmd[1] = index;
2610ebd0bab066cd86d7a19f4646e0686dae885004eThierry Strudel    cmd[2] = index >> 8;
2620ebd0bab066cd86d7a19f4646e0686dae885004eThierry Strudel    cmd[3] = len;
2630ebd0bab066cd86d7a19f4646e0686dae885004eThierry Strudel}
2640ebd0bab066cd86d7a19f4646e0686dae885004eThierry Strudel
2650ebd0bab066cd86d7a19f4646e0686dae885004eThierry Strudel
2660ebd0bab066cd86d7a19f4646e0686dae885004eThierry Strudelstatic int read_ps_event(uint8_t *event, uint16_t ocf)
2670ebd0bab066cd86d7a19f4646e0686dae885004eThierry Strudel{
2680ebd0bab066cd86d7a19f4646e0686dae885004eThierry Strudel    hci_event_hdr *eh;
2690ebd0bab066cd86d7a19f4646e0686dae885004eThierry Strudel    uint16_t opcode = htobs(cmd_opcode_pack(HCI_VENDOR_CMD_OGF, ocf));
2700ebd0bab066cd86d7a19f4646e0686dae885004eThierry Strudel
2710ebd0bab066cd86d7a19f4646e0686dae885004eThierry Strudel    event++;
2720ebd0bab066cd86d7a19f4646e0686dae885004eThierry Strudel
2730ebd0bab066cd86d7a19f4646e0686dae885004eThierry Strudel    eh = (void *)event;
2740ebd0bab066cd86d7a19f4646e0686dae885004eThierry Strudel    event += HCI_EVENT_HDR_SIZE;
2750ebd0bab066cd86d7a19f4646e0686dae885004eThierry Strudel
2760ebd0bab066cd86d7a19f4646e0686dae885004eThierry Strudel    if (eh->evt == EVT_CMD_COMPLETE) {
2770ebd0bab066cd86d7a19f4646e0686dae885004eThierry Strudel        evt_cmd_complete *cc = (void *)event;
2780ebd0bab066cd86d7a19f4646e0686dae885004eThierry Strudel
2790ebd0bab066cd86d7a19f4646e0686dae885004eThierry Strudel        event += EVT_CMD_COMPLETE_SIZE;
2800ebd0bab066cd86d7a19f4646e0686dae885004eThierry Strudel
2810ebd0bab066cd86d7a19f4646e0686dae885004eThierry Strudel        if (cc->opcode == opcode && event[0] == HCI_EV_SUCCESS)
2820ebd0bab066cd86d7a19f4646e0686dae885004eThierry Strudel            return 0;
2830ebd0bab066cd86d7a19f4646e0686dae885004eThierry Strudel        else
2840ebd0bab066cd86d7a19f4646e0686dae885004eThierry Strudel            return -EILSEQ;
2850ebd0bab066cd86d7a19f4646e0686dae885004eThierry Strudel    }
2860ebd0bab066cd86d7a19f4646e0686dae885004eThierry Strudel
2870ebd0bab066cd86d7a19f4646e0686dae885004eThierry Strudel    return -EILSEQ;
2880ebd0bab066cd86d7a19f4646e0686dae885004eThierry Strudel}
2890ebd0bab066cd86d7a19f4646e0686dae885004eThierry Strudel
2900ebd0bab066cd86d7a19f4646e0686dae885004eThierry Strudel#define PS_WRITE           1
2910ebd0bab066cd86d7a19f4646e0686dae885004eThierry Strudel#define PS_RESET           2
2920ebd0bab066cd86d7a19f4646e0686dae885004eThierry Strudel#define WRITE_PATCH        8
2930ebd0bab066cd86d7a19f4646e0686dae885004eThierry Strudel#define ENABLE_PATCH       11
2940ebd0bab066cd86d7a19f4646e0686dae885004eThierry Strudel
2950ebd0bab066cd86d7a19f4646e0686dae885004eThierry Strudel#define HCI_PS_CMD_HDR_LEN 7
2960ebd0bab066cd86d7a19f4646e0686dae885004eThierry Strudel
2970ebd0bab066cd86d7a19f4646e0686dae885004eThierry Strudelstatic int write_cmd(int fd, uint8_t *buffer, int len)
2980ebd0bab066cd86d7a19f4646e0686dae885004eThierry Strudel{
2990ebd0bab066cd86d7a19f4646e0686dae885004eThierry Strudel    uint8_t *event;
3000ebd0bab066cd86d7a19f4646e0686dae885004eThierry Strudel    int err;
3010ebd0bab066cd86d7a19f4646e0686dae885004eThierry Strudel
3020ebd0bab066cd86d7a19f4646e0686dae885004eThierry Strudel    err = send_hci_cmd_sync(fd, buffer, len, &event);
3030ebd0bab066cd86d7a19f4646e0686dae885004eThierry Strudel    if (err < 0)
3040ebd0bab066cd86d7a19f4646e0686dae885004eThierry Strudel        return err;
3050ebd0bab066cd86d7a19f4646e0686dae885004eThierry Strudel
3060ebd0bab066cd86d7a19f4646e0686dae885004eThierry Strudel    err = read_ps_event(event, HCI_PS_CMD_OCF);
3070ebd0bab066cd86d7a19f4646e0686dae885004eThierry Strudel
3080ebd0bab066cd86d7a19f4646e0686dae885004eThierry Strudel    free(event);
3090ebd0bab066cd86d7a19f4646e0686dae885004eThierry Strudel
3100ebd0bab066cd86d7a19f4646e0686dae885004eThierry Strudel    return err;
3110ebd0bab066cd86d7a19f4646e0686dae885004eThierry Strudel}
3120ebd0bab066cd86d7a19f4646e0686dae885004eThierry Strudel
3130ebd0bab066cd86d7a19f4646e0686dae885004eThierry Strudel#define PS_RESET_PARAM_LEN 6
3140ebd0bab066cd86d7a19f4646e0686dae885004eThierry Strudel#define PS_RESET_CMD_LEN   (HCI_PS_CMD_HDR_LEN + PS_RESET_PARAM_LEN)
3150ebd0bab066cd86d7a19f4646e0686dae885004eThierry Strudel
3160ebd0bab066cd86d7a19f4646e0686dae885004eThierry Strudel#define PS_ID_MASK         0xFF
3170ebd0bab066cd86d7a19f4646e0686dae885004eThierry Strudel
3180ebd0bab066cd86d7a19f4646e0686dae885004eThierry Strudel/* Sends PS commands using vendor specficic HCI commands */
3190ebd0bab066cd86d7a19f4646e0686dae885004eThierry Strudelstatic int write_ps_cmd(int fd, uint8_t opcode, uint32_t ps_param)
3200ebd0bab066cd86d7a19f4646e0686dae885004eThierry Strudel{
3210ebd0bab066cd86d7a19f4646e0686dae885004eThierry Strudel    uint8_t cmd[HCI_MAX_CMD_SIZE];
3220ebd0bab066cd86d7a19f4646e0686dae885004eThierry Strudel    uint32_t i;
3230ebd0bab066cd86d7a19f4646e0686dae885004eThierry Strudel
3240ebd0bab066cd86d7a19f4646e0686dae885004eThierry Strudel    switch (opcode) {
3250ebd0bab066cd86d7a19f4646e0686dae885004eThierry Strudel        case ENABLE_PATCH:
3260ebd0bab066cd86d7a19f4646e0686dae885004eThierry Strudel            load_hci_ps_hdr(cmd, opcode, 0, 0x00);
3270ebd0bab066cd86d7a19f4646e0686dae885004eThierry Strudel
3280ebd0bab066cd86d7a19f4646e0686dae885004eThierry Strudel            if (write_cmd(fd, cmd, HCI_PS_CMD_HDR_LEN) < 0)
3290ebd0bab066cd86d7a19f4646e0686dae885004eThierry Strudel                return -EILSEQ;
3300ebd0bab066cd86d7a19f4646e0686dae885004eThierry Strudel            break;
3310ebd0bab066cd86d7a19f4646e0686dae885004eThierry Strudel
3320ebd0bab066cd86d7a19f4646e0686dae885004eThierry Strudel        case PS_RESET:
3330ebd0bab066cd86d7a19f4646e0686dae885004eThierry Strudel            load_hci_ps_hdr(cmd, opcode, PS_RESET_PARAM_LEN, 0x00);
3340ebd0bab066cd86d7a19f4646e0686dae885004eThierry Strudel
3350ebd0bab066cd86d7a19f4646e0686dae885004eThierry Strudel            cmd[7] = 0x00;
3360ebd0bab066cd86d7a19f4646e0686dae885004eThierry Strudel            cmd[PS_RESET_CMD_LEN - 2] = ps_param & PS_ID_MASK;
3370ebd0bab066cd86d7a19f4646e0686dae885004eThierry Strudel            cmd[PS_RESET_CMD_LEN - 1] = (ps_param >> 8) & PS_ID_MASK;
3380ebd0bab066cd86d7a19f4646e0686dae885004eThierry Strudel
3390ebd0bab066cd86d7a19f4646e0686dae885004eThierry Strudel            if (write_cmd(fd, cmd, PS_RESET_CMD_LEN) < 0)
3400ebd0bab066cd86d7a19f4646e0686dae885004eThierry Strudel                return -EILSEQ;
3410ebd0bab066cd86d7a19f4646e0686dae885004eThierry Strudel            break;
3420ebd0bab066cd86d7a19f4646e0686dae885004eThierry Strudel
3430ebd0bab066cd86d7a19f4646e0686dae885004eThierry Strudel        case PS_WRITE:
3440ebd0bab066cd86d7a19f4646e0686dae885004eThierry Strudel            for (i = 0; i < ps_param; i++) {
3450ebd0bab066cd86d7a19f4646e0686dae885004eThierry Strudel                load_hci_ps_hdr(cmd, opcode, ps_list[i].len,
3460ebd0bab066cd86d7a19f4646e0686dae885004eThierry Strudel                ps_list[i].id);
3470ebd0bab066cd86d7a19f4646e0686dae885004eThierry Strudel
3480ebd0bab066cd86d7a19f4646e0686dae885004eThierry Strudel                memcpy(&cmd[HCI_PS_CMD_HDR_LEN], ps_list[i].data,
3490ebd0bab066cd86d7a19f4646e0686dae885004eThierry Strudel                ps_list[i].len);
3500ebd0bab066cd86d7a19f4646e0686dae885004eThierry Strudel
3510ebd0bab066cd86d7a19f4646e0686dae885004eThierry Strudel                if (write_cmd(fd, cmd, ps_list[i].len +
3520ebd0bab066cd86d7a19f4646e0686dae885004eThierry Strudel                    HCI_PS_CMD_HDR_LEN) < 0)
3530ebd0bab066cd86d7a19f4646e0686dae885004eThierry Strudel                    return -EILSEQ;
3540ebd0bab066cd86d7a19f4646e0686dae885004eThierry Strudel            }
3550ebd0bab066cd86d7a19f4646e0686dae885004eThierry Strudel            break;
3560ebd0bab066cd86d7a19f4646e0686dae885004eThierry Strudel    }
3570ebd0bab066cd86d7a19f4646e0686dae885004eThierry Strudel
3580ebd0bab066cd86d7a19f4646e0686dae885004eThierry Strudel    return 0;
3590ebd0bab066cd86d7a19f4646e0686dae885004eThierry Strudel}
3600ebd0bab066cd86d7a19f4646e0686dae885004eThierry Strudel
3610ebd0bab066cd86d7a19f4646e0686dae885004eThierry Strudel#define PS_ASIC_FILE    "PS_ASIC.pst"
3620ebd0bab066cd86d7a19f4646e0686dae885004eThierry Strudel#define PS_FPGA_FILE    "PS_FPGA.pst"
3630ebd0bab066cd86d7a19f4646e0686dae885004eThierry Strudel#define MAXPATHLEN  4096
3640ebd0bab066cd86d7a19f4646e0686dae885004eThierry Strudelstatic void get_ps_file_name(uint32_t devtype, uint32_t rom_version,char *path)
3650ebd0bab066cd86d7a19f4646e0686dae885004eThierry Strudel{
3660ebd0bab066cd86d7a19f4646e0686dae885004eThierry Strudel    char *filename;
3670ebd0bab066cd86d7a19f4646e0686dae885004eThierry Strudel
3680ebd0bab066cd86d7a19f4646e0686dae885004eThierry Strudel    if (devtype == 0xdeadc0de)
3690ebd0bab066cd86d7a19f4646e0686dae885004eThierry Strudel        filename = PS_ASIC_FILE;
3700ebd0bab066cd86d7a19f4646e0686dae885004eThierry Strudel    else
3710ebd0bab066cd86d7a19f4646e0686dae885004eThierry Strudel        filename = PS_FPGA_FILE;
3720ebd0bab066cd86d7a19f4646e0686dae885004eThierry Strudel
3730ebd0bab066cd86d7a19f4646e0686dae885004eThierry Strudel    snprintf(path, MAXPATHLEN, "%s%x/%s", FW_PATH, rom_version, filename);
3740ebd0bab066cd86d7a19f4646e0686dae885004eThierry Strudel}
3750ebd0bab066cd86d7a19f4646e0686dae885004eThierry Strudel
3760ebd0bab066cd86d7a19f4646e0686dae885004eThierry Strudel#define PATCH_FILE        "RamPatch.txt"
3770ebd0bab066cd86d7a19f4646e0686dae885004eThierry Strudel#define FPGA_ROM_VERSION  0x99999999
3780ebd0bab066cd86d7a19f4646e0686dae885004eThierry Strudel#define ROM_DEV_TYPE      0xdeadc0de
3790ebd0bab066cd86d7a19f4646e0686dae885004eThierry Strudel
3800ebd0bab066cd86d7a19f4646e0686dae885004eThierry Strudelstatic void get_patch_file_name(uint32_t dev_type, uint32_t rom_version,
3810ebd0bab066cd86d7a19f4646e0686dae885004eThierry Strudel    uint32_t build_version, char *path)
3820ebd0bab066cd86d7a19f4646e0686dae885004eThierry Strudel{
3830ebd0bab066cd86d7a19f4646e0686dae885004eThierry Strudel    if (rom_version == FPGA_ROM_VERSION && dev_type != ROM_DEV_TYPE
3840ebd0bab066cd86d7a19f4646e0686dae885004eThierry Strudel            &&dev_type != 0 && build_version == 1)
3850ebd0bab066cd86d7a19f4646e0686dae885004eThierry Strudel        path[0] = '\0';
3860ebd0bab066cd86d7a19f4646e0686dae885004eThierry Strudel    else
3870ebd0bab066cd86d7a19f4646e0686dae885004eThierry Strudel        snprintf(path, MAXPATHLEN, "%s%x/%s", FW_PATH, rom_version, PATCH_FILE);
3880ebd0bab066cd86d7a19f4646e0686dae885004eThierry Strudel}
3890ebd0bab066cd86d7a19f4646e0686dae885004eThierry Strudel
3900ebd0bab066cd86d7a19f4646e0686dae885004eThierry Strudelstatic int set_cntrlr_baud(int fd, int speed)
3910ebd0bab066cd86d7a19f4646e0686dae885004eThierry Strudel{
3920ebd0bab066cd86d7a19f4646e0686dae885004eThierry Strudel    int baud;
3930ebd0bab066cd86d7a19f4646e0686dae885004eThierry Strudel    struct timespec tm = { 0, 500000};
3940ebd0bab066cd86d7a19f4646e0686dae885004eThierry Strudel    unsigned char cmd[MAX_CMD_LEN], rsp[HCI_MAX_EVENT_SIZE];
3950ebd0bab066cd86d7a19f4646e0686dae885004eThierry Strudel    unsigned char *ptr = cmd + 1;
3960ebd0bab066cd86d7a19f4646e0686dae885004eThierry Strudel    hci_command_hdr *ch = (void *)ptr;
3970ebd0bab066cd86d7a19f4646e0686dae885004eThierry Strudel
3980ebd0bab066cd86d7a19f4646e0686dae885004eThierry Strudel    cmd[0] = HCI_COMMAND_PKT;
3990ebd0bab066cd86d7a19f4646e0686dae885004eThierry Strudel
4000ebd0bab066cd86d7a19f4646e0686dae885004eThierry Strudel    /* set controller baud rate to user specified value */
4010ebd0bab066cd86d7a19f4646e0686dae885004eThierry Strudel    ptr = cmd + 1;
4020ebd0bab066cd86d7a19f4646e0686dae885004eThierry Strudel    ch->opcode = htobs(cmd_opcode_pack(HCI_VENDOR_CMD_OGF,
4030ebd0bab066cd86d7a19f4646e0686dae885004eThierry Strudel    HCI_CHG_BAUD_CMD_OCF));
4040ebd0bab066cd86d7a19f4646e0686dae885004eThierry Strudel    ch->plen = 2;
4050ebd0bab066cd86d7a19f4646e0686dae885004eThierry Strudel    ptr += HCI_COMMAND_HDR_SIZE;
4060ebd0bab066cd86d7a19f4646e0686dae885004eThierry Strudel
4070ebd0bab066cd86d7a19f4646e0686dae885004eThierry Strudel    baud = speed/100;
4080ebd0bab066cd86d7a19f4646e0686dae885004eThierry Strudel    ptr[0] = (char)baud;
4090ebd0bab066cd86d7a19f4646e0686dae885004eThierry Strudel    ptr[1] = (char)(baud >> 8);
4100ebd0bab066cd86d7a19f4646e0686dae885004eThierry Strudel
4110ebd0bab066cd86d7a19f4646e0686dae885004eThierry Strudel    if (write(fd, cmd, WRITE_BAUD_CMD_LEN) != WRITE_BAUD_CMD_LEN) {
4120ebd0bab066cd86d7a19f4646e0686dae885004eThierry Strudel        ALOGI("Failed to write change baud rate command");
4130ebd0bab066cd86d7a19f4646e0686dae885004eThierry Strudel        return -ETIMEDOUT;
4140ebd0bab066cd86d7a19f4646e0686dae885004eThierry Strudel    }
4150ebd0bab066cd86d7a19f4646e0686dae885004eThierry Strudel
4160ebd0bab066cd86d7a19f4646e0686dae885004eThierry Strudel    nanosleep(&tm, NULL);
4170ebd0bab066cd86d7a19f4646e0686dae885004eThierry Strudel
4180ebd0bab066cd86d7a19f4646e0686dae885004eThierry Strudel    if (read_hci_event(fd, rsp, sizeof(rsp)) < 0)
4190ebd0bab066cd86d7a19f4646e0686dae885004eThierry Strudel        return -ETIMEDOUT;
4200ebd0bab066cd86d7a19f4646e0686dae885004eThierry Strudel
4210ebd0bab066cd86d7a19f4646e0686dae885004eThierry Strudel    return 0;
4220ebd0bab066cd86d7a19f4646e0686dae885004eThierry Strudel}
4230ebd0bab066cd86d7a19f4646e0686dae885004eThierry Strudel
4240ebd0bab066cd86d7a19f4646e0686dae885004eThierry Strudel#define PS_UNDEF   0
4250ebd0bab066cd86d7a19f4646e0686dae885004eThierry Strudel#define PS_ID      1
4260ebd0bab066cd86d7a19f4646e0686dae885004eThierry Strudel#define PS_LEN     2
4270ebd0bab066cd86d7a19f4646e0686dae885004eThierry Strudel#define PS_DATA    3
4280ebd0bab066cd86d7a19f4646e0686dae885004eThierry Strudel
4290ebd0bab066cd86d7a19f4646e0686dae885004eThierry Strudel#define PS_MAX_LEN         500
4300ebd0bab066cd86d7a19f4646e0686dae885004eThierry Strudel#define LINE_SIZE_MAX      (PS_MAX_LEN * 2)
4310ebd0bab066cd86d7a19f4646e0686dae885004eThierry Strudel#define ENTRY_PER_LINE     16
4320ebd0bab066cd86d7a19f4646e0686dae885004eThierry Strudel
4330ebd0bab066cd86d7a19f4646e0686dae885004eThierry Strudel#define __check_comment(buf) (((buf)[0] == '/') && ((buf)[1] == '/'))
4340ebd0bab066cd86d7a19f4646e0686dae885004eThierry Strudel#define __skip_space(str)      while (*(str) == ' ') ((str)++)
4350ebd0bab066cd86d7a19f4646e0686dae885004eThierry Strudel
4360ebd0bab066cd86d7a19f4646e0686dae885004eThierry Strudel
4370ebd0bab066cd86d7a19f4646e0686dae885004eThierry Strudel#define __is_delim(ch) ((ch) == ':')
4380ebd0bab066cd86d7a19f4646e0686dae885004eThierry Strudel#define MAX_PREAMBLE_LEN 4
4390ebd0bab066cd86d7a19f4646e0686dae885004eThierry Strudel
4400ebd0bab066cd86d7a19f4646e0686dae885004eThierry Strudel/* Parse PS entry preamble of format [X:X] for main type and subtype */
4410ebd0bab066cd86d7a19f4646e0686dae885004eThierry Strudelstatic int get_ps_type(char *ptr, int index, char *type, char *sub_type)
4420ebd0bab066cd86d7a19f4646e0686dae885004eThierry Strudel{
4430ebd0bab066cd86d7a19f4646e0686dae885004eThierry Strudel    int i;
4440ebd0bab066cd86d7a19f4646e0686dae885004eThierry Strudel    int delim = FALSE;
4450ebd0bab066cd86d7a19f4646e0686dae885004eThierry Strudel
4460ebd0bab066cd86d7a19f4646e0686dae885004eThierry Strudel    if (index > MAX_PREAMBLE_LEN)
4470ebd0bab066cd86d7a19f4646e0686dae885004eThierry Strudel        return -EILSEQ;
4480ebd0bab066cd86d7a19f4646e0686dae885004eThierry Strudel
4490ebd0bab066cd86d7a19f4646e0686dae885004eThierry Strudel    for (i = 1; i < index; i++) {
4500ebd0bab066cd86d7a19f4646e0686dae885004eThierry Strudel        if (__is_delim(ptr[i])) {
4510ebd0bab066cd86d7a19f4646e0686dae885004eThierry Strudel            delim = TRUE;
4520ebd0bab066cd86d7a19f4646e0686dae885004eThierry Strudel            continue;
4530ebd0bab066cd86d7a19f4646e0686dae885004eThierry Strudel        }
4540ebd0bab066cd86d7a19f4646e0686dae885004eThierry Strudel
4550ebd0bab066cd86d7a19f4646e0686dae885004eThierry Strudel        if (isalpha(ptr[i])) {
4560ebd0bab066cd86d7a19f4646e0686dae885004eThierry Strudel            if (delim == FALSE)
4570ebd0bab066cd86d7a19f4646e0686dae885004eThierry Strudel                (*type) = toupper(ptr[i]);
4580ebd0bab066cd86d7a19f4646e0686dae885004eThierry Strudel            else
4590ebd0bab066cd86d7a19f4646e0686dae885004eThierry Strudel                (*sub_type)	= toupper(ptr[i]);
4600ebd0bab066cd86d7a19f4646e0686dae885004eThierry Strudel        }
4610ebd0bab066cd86d7a19f4646e0686dae885004eThierry Strudel    }
4620ebd0bab066cd86d7a19f4646e0686dae885004eThierry Strudel
4630ebd0bab066cd86d7a19f4646e0686dae885004eThierry Strudel    return 0;
4640ebd0bab066cd86d7a19f4646e0686dae885004eThierry Strudel}
4650ebd0bab066cd86d7a19f4646e0686dae885004eThierry Strudel
4660ebd0bab066cd86d7a19f4646e0686dae885004eThierry Strudel#define ARRAY   'A'
4670ebd0bab066cd86d7a19f4646e0686dae885004eThierry Strudel#define STRING  'S'
4680ebd0bab066cd86d7a19f4646e0686dae885004eThierry Strudel#define DECIMAL 'D'
4690ebd0bab066cd86d7a19f4646e0686dae885004eThierry Strudel#define BINARY  'B'
4700ebd0bab066cd86d7a19f4646e0686dae885004eThierry Strudel
4710ebd0bab066cd86d7a19f4646e0686dae885004eThierry Strudel#define PS_HEX           0
4720ebd0bab066cd86d7a19f4646e0686dae885004eThierry Strudel#define PS_DEC           1
4730ebd0bab066cd86d7a19f4646e0686dae885004eThierry Strudel
4740ebd0bab066cd86d7a19f4646e0686dae885004eThierry Strudelstatic int get_input_format(char *buf, struct ps_entry_type *format)
4750ebd0bab066cd86d7a19f4646e0686dae885004eThierry Strudel{
4760ebd0bab066cd86d7a19f4646e0686dae885004eThierry Strudel    char *ptr = NULL;
4770ebd0bab066cd86d7a19f4646e0686dae885004eThierry Strudel    char type = '\0';
4780ebd0bab066cd86d7a19f4646e0686dae885004eThierry Strudel    char sub_type = '\0';
4790ebd0bab066cd86d7a19f4646e0686dae885004eThierry Strudel
4800ebd0bab066cd86d7a19f4646e0686dae885004eThierry Strudel    format->type = PS_HEX;
4810ebd0bab066cd86d7a19f4646e0686dae885004eThierry Strudel    format->array = TRUE;
4820ebd0bab066cd86d7a19f4646e0686dae885004eThierry Strudel
4830ebd0bab066cd86d7a19f4646e0686dae885004eThierry Strudel    if (strstr(buf, "[") != buf)
4840ebd0bab066cd86d7a19f4646e0686dae885004eThierry Strudel        return 0;
4850ebd0bab066cd86d7a19f4646e0686dae885004eThierry Strudel
4860ebd0bab066cd86d7a19f4646e0686dae885004eThierry Strudel    ptr = strstr(buf, "]");
4870ebd0bab066cd86d7a19f4646e0686dae885004eThierry Strudel    if (!ptr)
4880ebd0bab066cd86d7a19f4646e0686dae885004eThierry Strudel        return -EILSEQ;
4890ebd0bab066cd86d7a19f4646e0686dae885004eThierry Strudel
4900ebd0bab066cd86d7a19f4646e0686dae885004eThierry Strudel    if (get_ps_type(buf, ptr - buf, &type, &sub_type) < 0)
4910ebd0bab066cd86d7a19f4646e0686dae885004eThierry Strudel        return -EILSEQ;
4920ebd0bab066cd86d7a19f4646e0686dae885004eThierry Strudel
4930ebd0bab066cd86d7a19f4646e0686dae885004eThierry Strudel    /* Check is data type is of array */
4940ebd0bab066cd86d7a19f4646e0686dae885004eThierry Strudel    if (type == ARRAY || sub_type == ARRAY)
4950ebd0bab066cd86d7a19f4646e0686dae885004eThierry Strudel        format->array = TRUE;
4960ebd0bab066cd86d7a19f4646e0686dae885004eThierry Strudel
4970ebd0bab066cd86d7a19f4646e0686dae885004eThierry Strudel    if (type == STRING || sub_type == STRING)
4980ebd0bab066cd86d7a19f4646e0686dae885004eThierry Strudel        format->array = FALSE;
4990ebd0bab066cd86d7a19f4646e0686dae885004eThierry Strudel
5000ebd0bab066cd86d7a19f4646e0686dae885004eThierry Strudel    if (type == DECIMAL || type == BINARY)
5010ebd0bab066cd86d7a19f4646e0686dae885004eThierry Strudel        format->type = PS_DEC;
5020ebd0bab066cd86d7a19f4646e0686dae885004eThierry Strudel    else
5030ebd0bab066cd86d7a19f4646e0686dae885004eThierry Strudel        format->type = PS_HEX;
5040ebd0bab066cd86d7a19f4646e0686dae885004eThierry Strudel
5050ebd0bab066cd86d7a19f4646e0686dae885004eThierry Strudel    return 0;
5060ebd0bab066cd86d7a19f4646e0686dae885004eThierry Strudel}
5070ebd0bab066cd86d7a19f4646e0686dae885004eThierry Strudel
5080ebd0bab066cd86d7a19f4646e0686dae885004eThierry Strudel
5090ebd0bab066cd86d7a19f4646e0686dae885004eThierry Strudel
5100ebd0bab066cd86d7a19f4646e0686dae885004eThierry Strudel#define UNDEFINED 0xFFFF
5110ebd0bab066cd86d7a19f4646e0686dae885004eThierry Strudel
5120ebd0bab066cd86d7a19f4646e0686dae885004eThierry Strudelstatic unsigned int read_data_in_section(char *buf, struct ps_entry_type type)
5130ebd0bab066cd86d7a19f4646e0686dae885004eThierry Strudel{
5140ebd0bab066cd86d7a19f4646e0686dae885004eThierry Strudel    char *ptr = buf;
5150ebd0bab066cd86d7a19f4646e0686dae885004eThierry Strudel
5160ebd0bab066cd86d7a19f4646e0686dae885004eThierry Strudel    if (!buf)
5170ebd0bab066cd86d7a19f4646e0686dae885004eThierry Strudel        return UNDEFINED;
5180ebd0bab066cd86d7a19f4646e0686dae885004eThierry Strudel
5190ebd0bab066cd86d7a19f4646e0686dae885004eThierry Strudel    if (buf == strstr(buf, "[")) {
5200ebd0bab066cd86d7a19f4646e0686dae885004eThierry Strudel        ptr = strstr(buf, "]");
5210ebd0bab066cd86d7a19f4646e0686dae885004eThierry Strudel        if (!ptr)
5220ebd0bab066cd86d7a19f4646e0686dae885004eThierry Strudel            return UNDEFINED;
5230ebd0bab066cd86d7a19f4646e0686dae885004eThierry Strudel
5240ebd0bab066cd86d7a19f4646e0686dae885004eThierry Strudel        ptr++;
5250ebd0bab066cd86d7a19f4646e0686dae885004eThierry Strudel    }
5260ebd0bab066cd86d7a19f4646e0686dae885004eThierry Strudel
5270ebd0bab066cd86d7a19f4646e0686dae885004eThierry Strudel    if (type.type == PS_HEX && type.array != TRUE)
5280ebd0bab066cd86d7a19f4646e0686dae885004eThierry Strudel        return strtol(ptr, NULL, 16);
5290ebd0bab066cd86d7a19f4646e0686dae885004eThierry Strudel
5300ebd0bab066cd86d7a19f4646e0686dae885004eThierry Strudel    return UNDEFINED;
5310ebd0bab066cd86d7a19f4646e0686dae885004eThierry Strudel}
5320ebd0bab066cd86d7a19f4646e0686dae885004eThierry Strudel
5330ebd0bab066cd86d7a19f4646e0686dae885004eThierry Strudel
5340ebd0bab066cd86d7a19f4646e0686dae885004eThierry Strudel/* Read PS entries as string, convert and add to Hex array */
5350ebd0bab066cd86d7a19f4646e0686dae885004eThierry Strudelstatic void update_tag_data(struct ps_cfg_entry *tag,
5360ebd0bab066cd86d7a19f4646e0686dae885004eThierry Strudel    struct tag_info *info, const char *ptr)
5370ebd0bab066cd86d7a19f4646e0686dae885004eThierry Strudel{
5380ebd0bab066cd86d7a19f4646e0686dae885004eThierry Strudel    char buf[3];
5390ebd0bab066cd86d7a19f4646e0686dae885004eThierry Strudel
5400ebd0bab066cd86d7a19f4646e0686dae885004eThierry Strudel    buf[2] = '\0';
5410ebd0bab066cd86d7a19f4646e0686dae885004eThierry Strudel
5420ebd0bab066cd86d7a19f4646e0686dae885004eThierry Strudel    strlcpy(buf, &ptr[info->char_cnt],sizeof(buf));
5430ebd0bab066cd86d7a19f4646e0686dae885004eThierry Strudel    tag->data[info->byte_count] = strtol(buf, NULL, 16);
5440ebd0bab066cd86d7a19f4646e0686dae885004eThierry Strudel    info->char_cnt += 3;
5450ebd0bab066cd86d7a19f4646e0686dae885004eThierry Strudel    info->byte_count++;
5460ebd0bab066cd86d7a19f4646e0686dae885004eThierry Strudel
5470ebd0bab066cd86d7a19f4646e0686dae885004eThierry Strudel    strlcpy(buf, &ptr[info->char_cnt], sizeof(buf));
5480ebd0bab066cd86d7a19f4646e0686dae885004eThierry Strudel    tag->data[info->byte_count] = strtol(buf, NULL, 16);
5490ebd0bab066cd86d7a19f4646e0686dae885004eThierry Strudel    info->char_cnt += 3;
5500ebd0bab066cd86d7a19f4646e0686dae885004eThierry Strudel    info->byte_count++;
5510ebd0bab066cd86d7a19f4646e0686dae885004eThierry Strudel}
5520ebd0bab066cd86d7a19f4646e0686dae885004eThierry Strudel
5530ebd0bab066cd86d7a19f4646e0686dae885004eThierry Strudelstatic inline int update_char_count(const char *buf)
5540ebd0bab066cd86d7a19f4646e0686dae885004eThierry Strudel{
5550ebd0bab066cd86d7a19f4646e0686dae885004eThierry Strudel    char *end_ptr;
5560ebd0bab066cd86d7a19f4646e0686dae885004eThierry Strudel
5570ebd0bab066cd86d7a19f4646e0686dae885004eThierry Strudel    if (strstr(buf, "[") == buf) {
5580ebd0bab066cd86d7a19f4646e0686dae885004eThierry Strudel        end_ptr = strstr(buf, "]");
5590ebd0bab066cd86d7a19f4646e0686dae885004eThierry Strudel        if (!end_ptr)
5600ebd0bab066cd86d7a19f4646e0686dae885004eThierry Strudel            return 0;
5610ebd0bab066cd86d7a19f4646e0686dae885004eThierry Strudel        else
5620ebd0bab066cd86d7a19f4646e0686dae885004eThierry Strudel            return(end_ptr - buf) +	1;
5630ebd0bab066cd86d7a19f4646e0686dae885004eThierry Strudel    }
5640ebd0bab066cd86d7a19f4646e0686dae885004eThierry Strudel
5650ebd0bab066cd86d7a19f4646e0686dae885004eThierry Strudel    return 0;
5660ebd0bab066cd86d7a19f4646e0686dae885004eThierry Strudel}
5670ebd0bab066cd86d7a19f4646e0686dae885004eThierry Strudel
5680ebd0bab066cd86d7a19f4646e0686dae885004eThierry Strudel#define PS_HEX           0
5690ebd0bab066cd86d7a19f4646e0686dae885004eThierry Strudel#define PS_DEC           1
5700ebd0bab066cd86d7a19f4646e0686dae885004eThierry Strudel
5710ebd0bab066cd86d7a19f4646e0686dae885004eThierry Strudelstatic int ath_parse_ps(FILE *stream)
5720ebd0bab066cd86d7a19f4646e0686dae885004eThierry Strudel{
5730ebd0bab066cd86d7a19f4646e0686dae885004eThierry Strudel    char buf[LINE_SIZE_MAX + 1];
5740ebd0bab066cd86d7a19f4646e0686dae885004eThierry Strudel    char *ptr;
5750ebd0bab066cd86d7a19f4646e0686dae885004eThierry Strudel    uint8_t tag_cnt = 0;
5760ebd0bab066cd86d7a19f4646e0686dae885004eThierry Strudel    int16_t byte_count = 0;
5770ebd0bab066cd86d7a19f4646e0686dae885004eThierry Strudel    struct ps_entry_type format;
5780ebd0bab066cd86d7a19f4646e0686dae885004eThierry Strudel    struct tag_info status = { 0, 0, 0, 0};
5790ebd0bab066cd86d7a19f4646e0686dae885004eThierry Strudel
5800ebd0bab066cd86d7a19f4646e0686dae885004eThierry Strudel    do {
5810ebd0bab066cd86d7a19f4646e0686dae885004eThierry Strudel        int read_count;
5820ebd0bab066cd86d7a19f4646e0686dae885004eThierry Strudel        struct ps_cfg_entry *tag;
5830ebd0bab066cd86d7a19f4646e0686dae885004eThierry Strudel
5840ebd0bab066cd86d7a19f4646e0686dae885004eThierry Strudel        ptr = fgets(buf, LINE_SIZE_MAX, stream);
5850ebd0bab066cd86d7a19f4646e0686dae885004eThierry Strudel        if (!ptr)
5860ebd0bab066cd86d7a19f4646e0686dae885004eThierry Strudel            break;
5870ebd0bab066cd86d7a19f4646e0686dae885004eThierry Strudel
5880ebd0bab066cd86d7a19f4646e0686dae885004eThierry Strudel        __skip_space(ptr);
5890ebd0bab066cd86d7a19f4646e0686dae885004eThierry Strudel        if (__check_comment(ptr))
5900ebd0bab066cd86d7a19f4646e0686dae885004eThierry Strudel            continue;
5910ebd0bab066cd86d7a19f4646e0686dae885004eThierry Strudel
5920ebd0bab066cd86d7a19f4646e0686dae885004eThierry Strudel        /* Lines with a '#' will be followed by new PS entry */
5930ebd0bab066cd86d7a19f4646e0686dae885004eThierry Strudel        if (ptr == strstr(ptr, "#")) {
5940ebd0bab066cd86d7a19f4646e0686dae885004eThierry Strudel            if (status.section != PS_UNDEF) {
5950ebd0bab066cd86d7a19f4646e0686dae885004eThierry Strudel                return -EILSEQ;
5960ebd0bab066cd86d7a19f4646e0686dae885004eThierry Strudel            } else {
5970ebd0bab066cd86d7a19f4646e0686dae885004eThierry Strudel                status.section = PS_ID;
5980ebd0bab066cd86d7a19f4646e0686dae885004eThierry Strudel                continue;
5990ebd0bab066cd86d7a19f4646e0686dae885004eThierry Strudel            }
6000ebd0bab066cd86d7a19f4646e0686dae885004eThierry Strudel        }
6010ebd0bab066cd86d7a19f4646e0686dae885004eThierry Strudel
6020ebd0bab066cd86d7a19f4646e0686dae885004eThierry Strudel        tag = &ps_list[tag_cnt];
6030ebd0bab066cd86d7a19f4646e0686dae885004eThierry Strudel
6040ebd0bab066cd86d7a19f4646e0686dae885004eThierry Strudel        switch (status.section) {
6050ebd0bab066cd86d7a19f4646e0686dae885004eThierry Strudel            case PS_ID:
6060ebd0bab066cd86d7a19f4646e0686dae885004eThierry Strudel                if (get_input_format(ptr, &format) < 0)
6070ebd0bab066cd86d7a19f4646e0686dae885004eThierry Strudel                    return -EILSEQ;
6080ebd0bab066cd86d7a19f4646e0686dae885004eThierry Strudel
6090ebd0bab066cd86d7a19f4646e0686dae885004eThierry Strudel                tag->id = read_data_in_section(ptr, format);
6100ebd0bab066cd86d7a19f4646e0686dae885004eThierry Strudel                status.section = PS_LEN;
6110ebd0bab066cd86d7a19f4646e0686dae885004eThierry Strudel                break;
6120ebd0bab066cd86d7a19f4646e0686dae885004eThierry Strudel
6130ebd0bab066cd86d7a19f4646e0686dae885004eThierry Strudel            case PS_LEN:
6140ebd0bab066cd86d7a19f4646e0686dae885004eThierry Strudel                if (get_input_format(ptr, &format) < 0)
6150ebd0bab066cd86d7a19f4646e0686dae885004eThierry Strudel                    return -EILSEQ;
6160ebd0bab066cd86d7a19f4646e0686dae885004eThierry Strudel
6170ebd0bab066cd86d7a19f4646e0686dae885004eThierry Strudel                byte_count = read_data_in_section(ptr, format);
6180ebd0bab066cd86d7a19f4646e0686dae885004eThierry Strudel                if (byte_count > PS_MAX_LEN)
6190ebd0bab066cd86d7a19f4646e0686dae885004eThierry Strudel                    return -EILSEQ;
6200ebd0bab066cd86d7a19f4646e0686dae885004eThierry Strudel
6210ebd0bab066cd86d7a19f4646e0686dae885004eThierry Strudel                tag->len = byte_count;
6220ebd0bab066cd86d7a19f4646e0686dae885004eThierry Strudel                tag->data = (uint8_t *)malloc(byte_count);
6230ebd0bab066cd86d7a19f4646e0686dae885004eThierry Strudel
6240ebd0bab066cd86d7a19f4646e0686dae885004eThierry Strudel                status.section = PS_DATA;
6250ebd0bab066cd86d7a19f4646e0686dae885004eThierry Strudel                status.line_count = 0;
6260ebd0bab066cd86d7a19f4646e0686dae885004eThierry Strudel                break;
6270ebd0bab066cd86d7a19f4646e0686dae885004eThierry Strudel
6280ebd0bab066cd86d7a19f4646e0686dae885004eThierry Strudel            case PS_DATA:
6290ebd0bab066cd86d7a19f4646e0686dae885004eThierry Strudel            if (status.line_count == 0)
6300ebd0bab066cd86d7a19f4646e0686dae885004eThierry Strudel                if (get_input_format(ptr, &format) < 0)
6310ebd0bab066cd86d7a19f4646e0686dae885004eThierry Strudel                    return -EILSEQ;
6320ebd0bab066cd86d7a19f4646e0686dae885004eThierry Strudel
6330ebd0bab066cd86d7a19f4646e0686dae885004eThierry Strudel            __skip_space(ptr);
6340ebd0bab066cd86d7a19f4646e0686dae885004eThierry Strudel
6350ebd0bab066cd86d7a19f4646e0686dae885004eThierry Strudel            status.char_cnt = update_char_count(ptr);
6360ebd0bab066cd86d7a19f4646e0686dae885004eThierry Strudel
6370ebd0bab066cd86d7a19f4646e0686dae885004eThierry Strudel            read_count = (byte_count > ENTRY_PER_LINE) ?
6380ebd0bab066cd86d7a19f4646e0686dae885004eThierry Strudel            ENTRY_PER_LINE : byte_count;
6390ebd0bab066cd86d7a19f4646e0686dae885004eThierry Strudel
6400ebd0bab066cd86d7a19f4646e0686dae885004eThierry Strudel            if (format.type == PS_HEX && format.array == TRUE) {
6410ebd0bab066cd86d7a19f4646e0686dae885004eThierry Strudel                while (read_count > 0) {
6420ebd0bab066cd86d7a19f4646e0686dae885004eThierry Strudel                    update_tag_data(tag, &status, ptr);
6430ebd0bab066cd86d7a19f4646e0686dae885004eThierry Strudel                    read_count -= 2;
6440ebd0bab066cd86d7a19f4646e0686dae885004eThierry Strudel                }
6450ebd0bab066cd86d7a19f4646e0686dae885004eThierry Strudel
6460ebd0bab066cd86d7a19f4646e0686dae885004eThierry Strudel                if (byte_count > ENTRY_PER_LINE)
6470ebd0bab066cd86d7a19f4646e0686dae885004eThierry Strudel                    byte_count -= ENTRY_PER_LINE;
6480ebd0bab066cd86d7a19f4646e0686dae885004eThierry Strudel                else
6490ebd0bab066cd86d7a19f4646e0686dae885004eThierry Strudel                    byte_count = 0;
6500ebd0bab066cd86d7a19f4646e0686dae885004eThierry Strudel            }
6510ebd0bab066cd86d7a19f4646e0686dae885004eThierry Strudel
6520ebd0bab066cd86d7a19f4646e0686dae885004eThierry Strudel            status.line_count++;
6530ebd0bab066cd86d7a19f4646e0686dae885004eThierry Strudel
6540ebd0bab066cd86d7a19f4646e0686dae885004eThierry Strudel            if (byte_count == 0)
6550ebd0bab066cd86d7a19f4646e0686dae885004eThierry Strudel                memset(&status, 0x00, sizeof(struct tag_info));
6560ebd0bab066cd86d7a19f4646e0686dae885004eThierry Strudel
6570ebd0bab066cd86d7a19f4646e0686dae885004eThierry Strudel            if (status.section == PS_UNDEF)
6580ebd0bab066cd86d7a19f4646e0686dae885004eThierry Strudel                tag_cnt++;
6590ebd0bab066cd86d7a19f4646e0686dae885004eThierry Strudel
6600ebd0bab066cd86d7a19f4646e0686dae885004eThierry Strudel            if (tag_cnt == MAX_TAGS)
6610ebd0bab066cd86d7a19f4646e0686dae885004eThierry Strudel                return -EILSEQ;
6620ebd0bab066cd86d7a19f4646e0686dae885004eThierry Strudel            break;
6630ebd0bab066cd86d7a19f4646e0686dae885004eThierry Strudel        }
6640ebd0bab066cd86d7a19f4646e0686dae885004eThierry Strudel    } while (ptr);
6650ebd0bab066cd86d7a19f4646e0686dae885004eThierry Strudel
6660ebd0bab066cd86d7a19f4646e0686dae885004eThierry Strudel    return tag_cnt;
6670ebd0bab066cd86d7a19f4646e0686dae885004eThierry Strudel}
6680ebd0bab066cd86d7a19f4646e0686dae885004eThierry Strudel
6690ebd0bab066cd86d7a19f4646e0686dae885004eThierry Strudel#define PS_RAM_SIZE 2048
6700ebd0bab066cd86d7a19f4646e0686dae885004eThierry Strudel
6710ebd0bab066cd86d7a19f4646e0686dae885004eThierry Strudelstatic int ps_config_download(int fd, int tag_count)
6720ebd0bab066cd86d7a19f4646e0686dae885004eThierry Strudel{
6730ebd0bab066cd86d7a19f4646e0686dae885004eThierry Strudel    if (write_ps_cmd(fd, PS_RESET, PS_RAM_SIZE) < 0)
6740ebd0bab066cd86d7a19f4646e0686dae885004eThierry Strudel        return -1;
6750ebd0bab066cd86d7a19f4646e0686dae885004eThierry Strudel
6760ebd0bab066cd86d7a19f4646e0686dae885004eThierry Strudel    if (tag_count > 0)
6770ebd0bab066cd86d7a19f4646e0686dae885004eThierry Strudel        if (write_ps_cmd(fd, PS_WRITE, tag_count) < 0)
6780ebd0bab066cd86d7a19f4646e0686dae885004eThierry Strudel            return -1;
6790ebd0bab066cd86d7a19f4646e0686dae885004eThierry Strudel    return 0;
6800ebd0bab066cd86d7a19f4646e0686dae885004eThierry Strudel}
6810ebd0bab066cd86d7a19f4646e0686dae885004eThierry Strudel
6820ebd0bab066cd86d7a19f4646e0686dae885004eThierry Strudelstatic int write_bdaddr(int pConfig, char *bdaddr)
6830ebd0bab066cd86d7a19f4646e0686dae885004eThierry Strudel{
6840ebd0bab066cd86d7a19f4646e0686dae885004eThierry Strudel    uint8_t *event;
6850ebd0bab066cd86d7a19f4646e0686dae885004eThierry Strudel    int err;
6860ebd0bab066cd86d7a19f4646e0686dae885004eThierry Strudel    uint8_t cmd[13];
6870ebd0bab066cd86d7a19f4646e0686dae885004eThierry Strudel    uint8_t *ptr = cmd;
6880ebd0bab066cd86d7a19f4646e0686dae885004eThierry Strudel    hci_command_hdr *ch = (void *)cmd;
6890ebd0bab066cd86d7a19f4646e0686dae885004eThierry Strudel
6900ebd0bab066cd86d7a19f4646e0686dae885004eThierry Strudel    memset(cmd, 0, sizeof(cmd));
6910ebd0bab066cd86d7a19f4646e0686dae885004eThierry Strudel
6920ebd0bab066cd86d7a19f4646e0686dae885004eThierry Strudel    ch->opcode = htobs(cmd_opcode_pack(HCI_VENDOR_CMD_OGF,
6930ebd0bab066cd86d7a19f4646e0686dae885004eThierry Strudel        HCI_PS_CMD_OCF));
6940ebd0bab066cd86d7a19f4646e0686dae885004eThierry Strudel    ch->plen = 10;
6950ebd0bab066cd86d7a19f4646e0686dae885004eThierry Strudel    ptr += HCI_COMMAND_HDR_SIZE;
6960ebd0bab066cd86d7a19f4646e0686dae885004eThierry Strudel
6970ebd0bab066cd86d7a19f4646e0686dae885004eThierry Strudel    ptr[0] = 0x01;
6980ebd0bab066cd86d7a19f4646e0686dae885004eThierry Strudel    ptr[1] = 0x01;
6990ebd0bab066cd86d7a19f4646e0686dae885004eThierry Strudel    ptr[2] = 0x00;
7000ebd0bab066cd86d7a19f4646e0686dae885004eThierry Strudel    ptr[3] = 0x06;
7010ebd0bab066cd86d7a19f4646e0686dae885004eThierry Strudel
7020ebd0bab066cd86d7a19f4646e0686dae885004eThierry Strudel    convert_bdaddr(bdaddr, (char *)&ptr[4]);
7030ebd0bab066cd86d7a19f4646e0686dae885004eThierry Strudel
7040ebd0bab066cd86d7a19f4646e0686dae885004eThierry Strudel    err = send_hci_cmd_sync(pConfig, cmd, sizeof(cmd), &event);
7050ebd0bab066cd86d7a19f4646e0686dae885004eThierry Strudel    if (err < 0)
7060ebd0bab066cd86d7a19f4646e0686dae885004eThierry Strudel        return err;
7070ebd0bab066cd86d7a19f4646e0686dae885004eThierry Strudel
7080ebd0bab066cd86d7a19f4646e0686dae885004eThierry Strudel    err = read_ps_event(event, HCI_PS_CMD_OCF);
7090ebd0bab066cd86d7a19f4646e0686dae885004eThierry Strudel
7100ebd0bab066cd86d7a19f4646e0686dae885004eThierry Strudel    free(event);
7110ebd0bab066cd86d7a19f4646e0686dae885004eThierry Strudel
7120ebd0bab066cd86d7a19f4646e0686dae885004eThierry Strudel    return err;
7130ebd0bab066cd86d7a19f4646e0686dae885004eThierry Strudel}
7140ebd0bab066cd86d7a19f4646e0686dae885004eThierry Strudel
7150ebd0bab066cd86d7a19f4646e0686dae885004eThierry Strudelstatic void write_bdaddr_from_file(int rom_version, int fd)
7160ebd0bab066cd86d7a19f4646e0686dae885004eThierry Strudel{
7170ebd0bab066cd86d7a19f4646e0686dae885004eThierry Strudel    FILE *stream;
7180ebd0bab066cd86d7a19f4646e0686dae885004eThierry Strudel    char bdaddr[PATH_MAX];
7190ebd0bab066cd86d7a19f4646e0686dae885004eThierry Strudel    char bdaddr_file[PATH_MAX];
7200ebd0bab066cd86d7a19f4646e0686dae885004eThierry Strudel
7210ebd0bab066cd86d7a19f4646e0686dae885004eThierry Strudel    snprintf(bdaddr_file, MAXPATHLEN, "%s%x/%s",
7220ebd0bab066cd86d7a19f4646e0686dae885004eThierry Strudel    FW_PATH, rom_version, BDADDR_FILE);
7230ebd0bab066cd86d7a19f4646e0686dae885004eThierry Strudel
7240ebd0bab066cd86d7a19f4646e0686dae885004eThierry Strudel    stream = fopen(bdaddr_file, "r");
7250ebd0bab066cd86d7a19f4646e0686dae885004eThierry Strudel    if (!stream)
7260ebd0bab066cd86d7a19f4646e0686dae885004eThierry Strudel       return;
7270ebd0bab066cd86d7a19f4646e0686dae885004eThierry Strudel
7280ebd0bab066cd86d7a19f4646e0686dae885004eThierry Strudel    if (fgets(bdaddr, PATH_MAX - 1, stream))
7290ebd0bab066cd86d7a19f4646e0686dae885004eThierry Strudel        write_bdaddr(fd, bdaddr);
7300ebd0bab066cd86d7a19f4646e0686dae885004eThierry Strudel
7310ebd0bab066cd86d7a19f4646e0686dae885004eThierry Strudel    fclose(stream);
7320ebd0bab066cd86d7a19f4646e0686dae885004eThierry Strudel}
7330ebd0bab066cd86d7a19f4646e0686dae885004eThierry Strudel
7340ebd0bab066cd86d7a19f4646e0686dae885004eThierry Strudel#define HCI_EVT_CMD_CMPL_OPCODE                 3
7350ebd0bab066cd86d7a19f4646e0686dae885004eThierry Strudel#define HCI_EVT_CMD_CMPL_STATUS_RET_BYTE        5
7360ebd0bab066cd86d7a19f4646e0686dae885004eThierry Strudel
7370ebd0bab066cd86d7a19f4646e0686dae885004eThierry Strudelvoid baswap(bdaddr_t *dst, const bdaddr_t *src)
7380ebd0bab066cd86d7a19f4646e0686dae885004eThierry Strudel{
7390ebd0bab066cd86d7a19f4646e0686dae885004eThierry Strudel    register unsigned char *d = (unsigned char *) dst;
7400ebd0bab066cd86d7a19f4646e0686dae885004eThierry Strudel    register const unsigned char *s = (const unsigned char *) src;
7410ebd0bab066cd86d7a19f4646e0686dae885004eThierry Strudel    register int i;
7420ebd0bab066cd86d7a19f4646e0686dae885004eThierry Strudel    for (i = 0; i < 6; i++)
7430ebd0bab066cd86d7a19f4646e0686dae885004eThierry Strudel        d[i] = s[5-i];
7440ebd0bab066cd86d7a19f4646e0686dae885004eThierry Strudel}
7450ebd0bab066cd86d7a19f4646e0686dae885004eThierry Strudel
7460ebd0bab066cd86d7a19f4646e0686dae885004eThierry Strudel
7470ebd0bab066cd86d7a19f4646e0686dae885004eThierry Strudelint str2ba(const char *str, bdaddr_t *ba)
7480ebd0bab066cd86d7a19f4646e0686dae885004eThierry Strudel{
7490ebd0bab066cd86d7a19f4646e0686dae885004eThierry Strudel    uint8_t b[6];
7500ebd0bab066cd86d7a19f4646e0686dae885004eThierry Strudel    const char *ptr = str;
7510ebd0bab066cd86d7a19f4646e0686dae885004eThierry Strudel    int i;
7520ebd0bab066cd86d7a19f4646e0686dae885004eThierry Strudel
7530ebd0bab066cd86d7a19f4646e0686dae885004eThierry Strudel    for (i = 0; i < 6; i++) {
7540ebd0bab066cd86d7a19f4646e0686dae885004eThierry Strudel        b[i] = (uint8_t) strtol(ptr, NULL, 16);
7550ebd0bab066cd86d7a19f4646e0686dae885004eThierry Strudel        ptr = strchr(ptr, ':');
7560ebd0bab066cd86d7a19f4646e0686dae885004eThierry Strudel        if (i != 5 && !ptr)
7570ebd0bab066cd86d7a19f4646e0686dae885004eThierry Strudel            ptr = ":00:00:00:00:00";
7580ebd0bab066cd86d7a19f4646e0686dae885004eThierry Strudel        ptr++;
7590ebd0bab066cd86d7a19f4646e0686dae885004eThierry Strudel    }
7600ebd0bab066cd86d7a19f4646e0686dae885004eThierry Strudel    baswap(ba, (bdaddr_t *) b);
7610ebd0bab066cd86d7a19f4646e0686dae885004eThierry Strudel    return 0;
7620ebd0bab066cd86d7a19f4646e0686dae885004eThierry Strudel}
7630ebd0bab066cd86d7a19f4646e0686dae885004eThierry Strudel
7640ebd0bab066cd86d7a19f4646e0686dae885004eThierry Strudel#define DEV_REGISTER      0x4FFC
7650ebd0bab066cd86d7a19f4646e0686dae885004eThierry Strudel#define GET_DEV_TYPE_OCF  0x05
7660ebd0bab066cd86d7a19f4646e0686dae885004eThierry Strudel
7670ebd0bab066cd86d7a19f4646e0686dae885004eThierry Strudelstatic int get_device_type(int dev, uint32_t *code)
7680ebd0bab066cd86d7a19f4646e0686dae885004eThierry Strudel{
7690ebd0bab066cd86d7a19f4646e0686dae885004eThierry Strudel    uint8_t cmd[8] = {0};
7700ebd0bab066cd86d7a19f4646e0686dae885004eThierry Strudel    uint8_t *event;
7710ebd0bab066cd86d7a19f4646e0686dae885004eThierry Strudel    uint32_t reg;
7720ebd0bab066cd86d7a19f4646e0686dae885004eThierry Strudel    int err;
7730ebd0bab066cd86d7a19f4646e0686dae885004eThierry Strudel    uint8_t *ptr = cmd;
7740ebd0bab066cd86d7a19f4646e0686dae885004eThierry Strudel    hci_command_hdr *ch = (void *)cmd;
7750ebd0bab066cd86d7a19f4646e0686dae885004eThierry Strudel
7760ebd0bab066cd86d7a19f4646e0686dae885004eThierry Strudel    ch->opcode = htobs(cmd_opcode_pack(HCI_VENDOR_CMD_OGF,
7770ebd0bab066cd86d7a19f4646e0686dae885004eThierry Strudel        GET_DEV_TYPE_OCF));
7780ebd0bab066cd86d7a19f4646e0686dae885004eThierry Strudel    ch->plen = 5;
7790ebd0bab066cd86d7a19f4646e0686dae885004eThierry Strudel    ptr += HCI_COMMAND_HDR_SIZE;
7800ebd0bab066cd86d7a19f4646e0686dae885004eThierry Strudel
7810ebd0bab066cd86d7a19f4646e0686dae885004eThierry Strudel    ptr[0] = (uint8_t)DEV_REGISTER;
7820ebd0bab066cd86d7a19f4646e0686dae885004eThierry Strudel    ptr[1] = (uint8_t)DEV_REGISTER >> 8;
7830ebd0bab066cd86d7a19f4646e0686dae885004eThierry Strudel    ptr[2] = (uint8_t)DEV_REGISTER >> 16;
7840ebd0bab066cd86d7a19f4646e0686dae885004eThierry Strudel    ptr[3] = (uint8_t)DEV_REGISTER >> 24;
7850ebd0bab066cd86d7a19f4646e0686dae885004eThierry Strudel    ptr[4] = 0x04;
7860ebd0bab066cd86d7a19f4646e0686dae885004eThierry Strudel
7870ebd0bab066cd86d7a19f4646e0686dae885004eThierry Strudel    err = send_hci_cmd_sync(dev, cmd, sizeof(cmd), &event);
7880ebd0bab066cd86d7a19f4646e0686dae885004eThierry Strudel    if (err < 0)
7890ebd0bab066cd86d7a19f4646e0686dae885004eThierry Strudel        return err;
7900ebd0bab066cd86d7a19f4646e0686dae885004eThierry Strudel
7910ebd0bab066cd86d7a19f4646e0686dae885004eThierry Strudel    err = read_ps_event(event, GET_DEV_TYPE_OCF);
7920ebd0bab066cd86d7a19f4646e0686dae885004eThierry Strudel    if (err < 0)
7930ebd0bab066cd86d7a19f4646e0686dae885004eThierry Strudel        goto cleanup;
7940ebd0bab066cd86d7a19f4646e0686dae885004eThierry Strudel
7950ebd0bab066cd86d7a19f4646e0686dae885004eThierry Strudel    reg = event[10];
7960ebd0bab066cd86d7a19f4646e0686dae885004eThierry Strudel    reg = (reg << 8) | event[9];
7970ebd0bab066cd86d7a19f4646e0686dae885004eThierry Strudel    reg = (reg << 8) | event[8];
7980ebd0bab066cd86d7a19f4646e0686dae885004eThierry Strudel    reg = (reg << 8) | event[7];
7990ebd0bab066cd86d7a19f4646e0686dae885004eThierry Strudel    *code = reg;
8000ebd0bab066cd86d7a19f4646e0686dae885004eThierry Strudel
8010ebd0bab066cd86d7a19f4646e0686dae885004eThierry Strudelcleanup:
8020ebd0bab066cd86d7a19f4646e0686dae885004eThierry Strudel    free(event);
8030ebd0bab066cd86d7a19f4646e0686dae885004eThierry Strudel
8040ebd0bab066cd86d7a19f4646e0686dae885004eThierry Strudel    return err;
8050ebd0bab066cd86d7a19f4646e0686dae885004eThierry Strudel}
8060ebd0bab066cd86d7a19f4646e0686dae885004eThierry Strudel
8070ebd0bab066cd86d7a19f4646e0686dae885004eThierry Strudel#define GET_VERSION_OCF 0x1E
8080ebd0bab066cd86d7a19f4646e0686dae885004eThierry Strudel
8090ebd0bab066cd86d7a19f4646e0686dae885004eThierry Strudelstatic int read_ath3k_version(int pConfig, uint32_t *rom_version,
8100ebd0bab066cd86d7a19f4646e0686dae885004eThierry Strudel    uint32_t *build_version)
8110ebd0bab066cd86d7a19f4646e0686dae885004eThierry Strudel{
8120ebd0bab066cd86d7a19f4646e0686dae885004eThierry Strudel    uint8_t cmd[3] = {0};
8130ebd0bab066cd86d7a19f4646e0686dae885004eThierry Strudel    uint8_t *event;
8140ebd0bab066cd86d7a19f4646e0686dae885004eThierry Strudel    int err;
8150ebd0bab066cd86d7a19f4646e0686dae885004eThierry Strudel    int status;
8160ebd0bab066cd86d7a19f4646e0686dae885004eThierry Strudel    hci_command_hdr *ch = (void *)cmd;
8170ebd0bab066cd86d7a19f4646e0686dae885004eThierry Strudel
8180ebd0bab066cd86d7a19f4646e0686dae885004eThierry Strudel    ch->opcode = htobs(cmd_opcode_pack(HCI_VENDOR_CMD_OGF,
8190ebd0bab066cd86d7a19f4646e0686dae885004eThierry Strudel    GET_VERSION_OCF));
8200ebd0bab066cd86d7a19f4646e0686dae885004eThierry Strudel    ch->plen = 0;
8210ebd0bab066cd86d7a19f4646e0686dae885004eThierry Strudel
8220ebd0bab066cd86d7a19f4646e0686dae885004eThierry Strudel    err = send_hci_cmd_sync(pConfig, cmd, sizeof(cmd), &event);
8230ebd0bab066cd86d7a19f4646e0686dae885004eThierry Strudel    if (err < 0)
8240ebd0bab066cd86d7a19f4646e0686dae885004eThierry Strudel        return err;
8250ebd0bab066cd86d7a19f4646e0686dae885004eThierry Strudel
8260ebd0bab066cd86d7a19f4646e0686dae885004eThierry Strudel    err = read_ps_event(event, GET_VERSION_OCF);
8270ebd0bab066cd86d7a19f4646e0686dae885004eThierry Strudel    if (err < 0)
8280ebd0bab066cd86d7a19f4646e0686dae885004eThierry Strudel        goto cleanup;
8290ebd0bab066cd86d7a19f4646e0686dae885004eThierry Strudel
8300ebd0bab066cd86d7a19f4646e0686dae885004eThierry Strudel    status = event[10];
8310ebd0bab066cd86d7a19f4646e0686dae885004eThierry Strudel    status = (status << 8) | event[9];
8320ebd0bab066cd86d7a19f4646e0686dae885004eThierry Strudel    status = (status << 8) | event[8];
8330ebd0bab066cd86d7a19f4646e0686dae885004eThierry Strudel    status = (status << 8) | event[7];
8340ebd0bab066cd86d7a19f4646e0686dae885004eThierry Strudel    *rom_version = status;
8350ebd0bab066cd86d7a19f4646e0686dae885004eThierry Strudel
8360ebd0bab066cd86d7a19f4646e0686dae885004eThierry Strudel    status = event[14];
8370ebd0bab066cd86d7a19f4646e0686dae885004eThierry Strudel    status = (status << 8) | event[13];
8380ebd0bab066cd86d7a19f4646e0686dae885004eThierry Strudel    status = (status << 8) | event[12];
8390ebd0bab066cd86d7a19f4646e0686dae885004eThierry Strudel    status = (status << 8) | event[11];
8400ebd0bab066cd86d7a19f4646e0686dae885004eThierry Strudel    *build_version = status;
8410ebd0bab066cd86d7a19f4646e0686dae885004eThierry Strudel
8420ebd0bab066cd86d7a19f4646e0686dae885004eThierry Strudelcleanup:
8430ebd0bab066cd86d7a19f4646e0686dae885004eThierry Strudel    free(event);
8440ebd0bab066cd86d7a19f4646e0686dae885004eThierry Strudel
8450ebd0bab066cd86d7a19f4646e0686dae885004eThierry Strudel    return err;
8460ebd0bab066cd86d7a19f4646e0686dae885004eThierry Strudel}
8470ebd0bab066cd86d7a19f4646e0686dae885004eThierry Strudel
8480ebd0bab066cd86d7a19f4646e0686dae885004eThierry Strudel#define VERIFY_CRC   9
8490ebd0bab066cd86d7a19f4646e0686dae885004eThierry Strudel#define PS_REGION    1
8500ebd0bab066cd86d7a19f4646e0686dae885004eThierry Strudel#define PATCH_REGION 2
8510ebd0bab066cd86d7a19f4646e0686dae885004eThierry Strudel
8520ebd0bab066cd86d7a19f4646e0686dae885004eThierry Strudelstatic int get_ath3k_crc(int dev)
8530ebd0bab066cd86d7a19f4646e0686dae885004eThierry Strudel{
8540ebd0bab066cd86d7a19f4646e0686dae885004eThierry Strudel    uint8_t cmd[7] = {0};
8550ebd0bab066cd86d7a19f4646e0686dae885004eThierry Strudel    uint8_t *event;
8560ebd0bab066cd86d7a19f4646e0686dae885004eThierry Strudel    int err;
8570ebd0bab066cd86d7a19f4646e0686dae885004eThierry Strudel
8580ebd0bab066cd86d7a19f4646e0686dae885004eThierry Strudel    load_hci_ps_hdr(cmd, VERIFY_CRC, 0, PS_REGION | PATCH_REGION);
8590ebd0bab066cd86d7a19f4646e0686dae885004eThierry Strudel
8600ebd0bab066cd86d7a19f4646e0686dae885004eThierry Strudel    err = send_hci_cmd_sync(dev, cmd, sizeof(cmd), &event);
8610ebd0bab066cd86d7a19f4646e0686dae885004eThierry Strudel    if (err < 0)
8620ebd0bab066cd86d7a19f4646e0686dae885004eThierry Strudel        return err;
8630ebd0bab066cd86d7a19f4646e0686dae885004eThierry Strudel    /* Send error code if CRC check patched */
8640ebd0bab066cd86d7a19f4646e0686dae885004eThierry Strudel    if (read_ps_event(event, HCI_PS_CMD_OCF) >= 0)
8650ebd0bab066cd86d7a19f4646e0686dae885004eThierry Strudel        err = -EILSEQ;
8660ebd0bab066cd86d7a19f4646e0686dae885004eThierry Strudel
8670ebd0bab066cd86d7a19f4646e0686dae885004eThierry Strudel    free(event);
8680ebd0bab066cd86d7a19f4646e0686dae885004eThierry Strudel
8690ebd0bab066cd86d7a19f4646e0686dae885004eThierry Strudel    return err;
8700ebd0bab066cd86d7a19f4646e0686dae885004eThierry Strudel}
8710ebd0bab066cd86d7a19f4646e0686dae885004eThierry Strudel
8720ebd0bab066cd86d7a19f4646e0686dae885004eThierry Strudel#define SET_PATCH_RAM_ID        0x0D
8730ebd0bab066cd86d7a19f4646e0686dae885004eThierry Strudel#define SET_PATCH_RAM_CMD_SIZE  11
8740ebd0bab066cd86d7a19f4646e0686dae885004eThierry Strudel#define ADDRESS_LEN             4
8750ebd0bab066cd86d7a19f4646e0686dae885004eThierry Strudelstatic int set_patch_ram(int dev, char *patch_loc, int len)
8760ebd0bab066cd86d7a19f4646e0686dae885004eThierry Strudel{
8770ebd0bab066cd86d7a19f4646e0686dae885004eThierry Strudel    int err;
8780ebd0bab066cd86d7a19f4646e0686dae885004eThierry Strudel    uint8_t cmd[20] = {0};
8790ebd0bab066cd86d7a19f4646e0686dae885004eThierry Strudel    int i, j;
8800ebd0bab066cd86d7a19f4646e0686dae885004eThierry Strudel    char loc_byte[3];
8810ebd0bab066cd86d7a19f4646e0686dae885004eThierry Strudel    uint8_t *event;
8820ebd0bab066cd86d7a19f4646e0686dae885004eThierry Strudel    uint8_t *loc_ptr = &cmd[7];
8830ebd0bab066cd86d7a19f4646e0686dae885004eThierry Strudel
8840ebd0bab066cd86d7a19f4646e0686dae885004eThierry Strudel    RESERVED(len);
8850ebd0bab066cd86d7a19f4646e0686dae885004eThierry Strudel
8860ebd0bab066cd86d7a19f4646e0686dae885004eThierry Strudel    if (!patch_loc)
8870ebd0bab066cd86d7a19f4646e0686dae885004eThierry Strudel        return -1;
8880ebd0bab066cd86d7a19f4646e0686dae885004eThierry Strudel
8890ebd0bab066cd86d7a19f4646e0686dae885004eThierry Strudel    loc_byte[2] = '\0';
8900ebd0bab066cd86d7a19f4646e0686dae885004eThierry Strudel
8910ebd0bab066cd86d7a19f4646e0686dae885004eThierry Strudel    load_hci_ps_hdr(cmd, SET_PATCH_RAM_ID, ADDRESS_LEN, 0);
8920ebd0bab066cd86d7a19f4646e0686dae885004eThierry Strudel
8930ebd0bab066cd86d7a19f4646e0686dae885004eThierry Strudel    for (i = 0, j = 3; i < 4; i++, j--) {
8940ebd0bab066cd86d7a19f4646e0686dae885004eThierry Strudel        loc_byte[0] = patch_loc[0];
8950ebd0bab066cd86d7a19f4646e0686dae885004eThierry Strudel        loc_byte[1] = patch_loc[1];
8960ebd0bab066cd86d7a19f4646e0686dae885004eThierry Strudel        loc_ptr[j] = strtol(loc_byte, NULL, 16);
8970ebd0bab066cd86d7a19f4646e0686dae885004eThierry Strudel        patch_loc += 2;
8980ebd0bab066cd86d7a19f4646e0686dae885004eThierry Strudel    }
8990ebd0bab066cd86d7a19f4646e0686dae885004eThierry Strudel
9000ebd0bab066cd86d7a19f4646e0686dae885004eThierry Strudel    err = send_hci_cmd_sync(dev, cmd, SET_PATCH_RAM_CMD_SIZE, &event);
9010ebd0bab066cd86d7a19f4646e0686dae885004eThierry Strudel    if (err < 0)
9020ebd0bab066cd86d7a19f4646e0686dae885004eThierry Strudel        return err;
9030ebd0bab066cd86d7a19f4646e0686dae885004eThierry Strudel
9040ebd0bab066cd86d7a19f4646e0686dae885004eThierry Strudel    err = read_ps_event(event, HCI_PS_CMD_OCF);
9050ebd0bab066cd86d7a19f4646e0686dae885004eThierry Strudel
9060ebd0bab066cd86d7a19f4646e0686dae885004eThierry Strudel    free(event);
9070ebd0bab066cd86d7a19f4646e0686dae885004eThierry Strudel
9080ebd0bab066cd86d7a19f4646e0686dae885004eThierry Strudel    return err;
9090ebd0bab066cd86d7a19f4646e0686dae885004eThierry Strudel}
9100ebd0bab066cd86d7a19f4646e0686dae885004eThierry Strudel
9110ebd0bab066cd86d7a19f4646e0686dae885004eThierry Strudel#define PATCH_LOC_KEY    "DA:"
9120ebd0bab066cd86d7a19f4646e0686dae885004eThierry Strudel#define PATCH_LOC_STRING_LEN    8
9130ebd0bab066cd86d7a19f4646e0686dae885004eThierry Strudelstatic int ps_patch_download(int fd, FILE *stream)
9140ebd0bab066cd86d7a19f4646e0686dae885004eThierry Strudel{
9150ebd0bab066cd86d7a19f4646e0686dae885004eThierry Strudel    char byte[3];
9160ebd0bab066cd86d7a19f4646e0686dae885004eThierry Strudel    char ptr[MAX_PATCH_CMD + 1];
9170ebd0bab066cd86d7a19f4646e0686dae885004eThierry Strudel    int byte_cnt;
9180ebd0bab066cd86d7a19f4646e0686dae885004eThierry Strudel    int patch_count = 0;
9190ebd0bab066cd86d7a19f4646e0686dae885004eThierry Strudel    char patch_loc[PATCH_LOC_STRING_LEN + 1];
9200ebd0bab066cd86d7a19f4646e0686dae885004eThierry Strudel
9210ebd0bab066cd86d7a19f4646e0686dae885004eThierry Strudel    byte[2] = '\0';
9220ebd0bab066cd86d7a19f4646e0686dae885004eThierry Strudel
9230ebd0bab066cd86d7a19f4646e0686dae885004eThierry Strudel    while (fgets(ptr, MAX_PATCH_CMD, stream)) {
9240ebd0bab066cd86d7a19f4646e0686dae885004eThierry Strudel        if (strlen(ptr) <= 1)
9250ebd0bab066cd86d7a19f4646e0686dae885004eThierry Strudel            continue;
9260ebd0bab066cd86d7a19f4646e0686dae885004eThierry Strudel        else if (strstr(ptr, PATCH_LOC_KEY) == ptr) {
9270ebd0bab066cd86d7a19f4646e0686dae885004eThierry Strudel            strlcpy(patch_loc, &ptr[sizeof(PATCH_LOC_KEY) - 1],
9280ebd0bab066cd86d7a19f4646e0686dae885004eThierry Strudel                PATCH_LOC_STRING_LEN);
9290ebd0bab066cd86d7a19f4646e0686dae885004eThierry Strudel            if (set_patch_ram(fd, patch_loc, sizeof(patch_loc)) < 0)
9300ebd0bab066cd86d7a19f4646e0686dae885004eThierry Strudel                return -1;
9310ebd0bab066cd86d7a19f4646e0686dae885004eThierry Strudel        } else if (isxdigit(ptr[0]))
9320ebd0bab066cd86d7a19f4646e0686dae885004eThierry Strudel            break;
9330ebd0bab066cd86d7a19f4646e0686dae885004eThierry Strudel        else
9340ebd0bab066cd86d7a19f4646e0686dae885004eThierry Strudel        return -1;
9350ebd0bab066cd86d7a19f4646e0686dae885004eThierry Strudel    }
9360ebd0bab066cd86d7a19f4646e0686dae885004eThierry Strudel
9370ebd0bab066cd86d7a19f4646e0686dae885004eThierry Strudel    byte_cnt = strtol(ptr, NULL, 16);
9380ebd0bab066cd86d7a19f4646e0686dae885004eThierry Strudel
9390ebd0bab066cd86d7a19f4646e0686dae885004eThierry Strudel    while (byte_cnt > 0) {
9400ebd0bab066cd86d7a19f4646e0686dae885004eThierry Strudel        int i;
9410ebd0bab066cd86d7a19f4646e0686dae885004eThierry Strudel        uint8_t cmd[HCI_MAX_CMD_SIZE] = {0};
9420ebd0bab066cd86d7a19f4646e0686dae885004eThierry Strudel        struct patch_entry patch;
9430ebd0bab066cd86d7a19f4646e0686dae885004eThierry Strudel
9440ebd0bab066cd86d7a19f4646e0686dae885004eThierry Strudel        if (byte_cnt > MAX_PATCH_CMD)
9450ebd0bab066cd86d7a19f4646e0686dae885004eThierry Strudel            patch.len = MAX_PATCH_CMD;
9460ebd0bab066cd86d7a19f4646e0686dae885004eThierry Strudel        else
9470ebd0bab066cd86d7a19f4646e0686dae885004eThierry Strudel            patch.len = byte_cnt;
9480ebd0bab066cd86d7a19f4646e0686dae885004eThierry Strudel
9490ebd0bab066cd86d7a19f4646e0686dae885004eThierry Strudel        for (i = 0; i < patch.len; i++) {
9500ebd0bab066cd86d7a19f4646e0686dae885004eThierry Strudel            if (!fgets(byte, 3, stream))
9510ebd0bab066cd86d7a19f4646e0686dae885004eThierry Strudel                return -1;
9520ebd0bab066cd86d7a19f4646e0686dae885004eThierry Strudel
9530ebd0bab066cd86d7a19f4646e0686dae885004eThierry Strudel            patch.data[i] = strtoul(byte, NULL, 16);
9540ebd0bab066cd86d7a19f4646e0686dae885004eThierry Strudel        }
9550ebd0bab066cd86d7a19f4646e0686dae885004eThierry Strudel
9560ebd0bab066cd86d7a19f4646e0686dae885004eThierry Strudel        load_hci_ps_hdr(cmd, WRITE_PATCH, patch.len, patch_count);
9570ebd0bab066cd86d7a19f4646e0686dae885004eThierry Strudel        memcpy(&cmd[HCI_PS_CMD_HDR_LEN], patch.data, patch.len);
9580ebd0bab066cd86d7a19f4646e0686dae885004eThierry Strudel
9590ebd0bab066cd86d7a19f4646e0686dae885004eThierry Strudel        if (write_cmd(fd, cmd, patch.len + HCI_PS_CMD_HDR_LEN) < 0)
9600ebd0bab066cd86d7a19f4646e0686dae885004eThierry Strudel            return -1;
9610ebd0bab066cd86d7a19f4646e0686dae885004eThierry Strudel
9620ebd0bab066cd86d7a19f4646e0686dae885004eThierry Strudel        patch_count++;
9630ebd0bab066cd86d7a19f4646e0686dae885004eThierry Strudel        byte_cnt = byte_cnt - MAX_PATCH_CMD;
9640ebd0bab066cd86d7a19f4646e0686dae885004eThierry Strudel    }
9650ebd0bab066cd86d7a19f4646e0686dae885004eThierry Strudel
9660ebd0bab066cd86d7a19f4646e0686dae885004eThierry Strudel    if (write_ps_cmd(fd, ENABLE_PATCH, 0) < 0)
9670ebd0bab066cd86d7a19f4646e0686dae885004eThierry Strudel        return -1;
9680ebd0bab066cd86d7a19f4646e0686dae885004eThierry Strudel
9690ebd0bab066cd86d7a19f4646e0686dae885004eThierry Strudel    return patch_count;
9700ebd0bab066cd86d7a19f4646e0686dae885004eThierry Strudel}
9710ebd0bab066cd86d7a19f4646e0686dae885004eThierry Strudel
9720ebd0bab066cd86d7a19f4646e0686dae885004eThierry Strudelstatic int ath_ps_download(int fd)
9730ebd0bab066cd86d7a19f4646e0686dae885004eThierry Strudel{
9740ebd0bab066cd86d7a19f4646e0686dae885004eThierry Strudel    int err = 0;
9750ebd0bab066cd86d7a19f4646e0686dae885004eThierry Strudel    int tag_count;
9760ebd0bab066cd86d7a19f4646e0686dae885004eThierry Strudel    int patch_count = 0;
9770ebd0bab066cd86d7a19f4646e0686dae885004eThierry Strudel    uint32_t rom_version = 0;
9780ebd0bab066cd86d7a19f4646e0686dae885004eThierry Strudel    uint32_t build_version = 0;
9790ebd0bab066cd86d7a19f4646e0686dae885004eThierry Strudel    uint32_t dev_type = 0;
9800ebd0bab066cd86d7a19f4646e0686dae885004eThierry Strudel    char patch_file[PATH_MAX];
9810ebd0bab066cd86d7a19f4646e0686dae885004eThierry Strudel    char ps_file[PATH_MAX];
9820ebd0bab066cd86d7a19f4646e0686dae885004eThierry Strudel    FILE *stream;
9830ebd0bab066cd86d7a19f4646e0686dae885004eThierry Strudel
9840ebd0bab066cd86d7a19f4646e0686dae885004eThierry Strudel    /*
9850ebd0bab066cd86d7a19f4646e0686dae885004eThierry Strudel    * Verfiy firmware version. depending on it select the PS
9860ebd0bab066cd86d7a19f4646e0686dae885004eThierry Strudel    * config file to download.
9870ebd0bab066cd86d7a19f4646e0686dae885004eThierry Strudel    */
9880ebd0bab066cd86d7a19f4646e0686dae885004eThierry Strudel    if (get_device_type(fd, &dev_type) < 0) {
9890ebd0bab066cd86d7a19f4646e0686dae885004eThierry Strudel        err = -EILSEQ;
9900ebd0bab066cd86d7a19f4646e0686dae885004eThierry Strudel        goto download_cmplete;
9910ebd0bab066cd86d7a19f4646e0686dae885004eThierry Strudel    }
9920ebd0bab066cd86d7a19f4646e0686dae885004eThierry Strudel
9930ebd0bab066cd86d7a19f4646e0686dae885004eThierry Strudel    if (read_ath3k_version(fd, &rom_version, &build_version) < 0) {
9940ebd0bab066cd86d7a19f4646e0686dae885004eThierry Strudel        err = -EILSEQ;
9950ebd0bab066cd86d7a19f4646e0686dae885004eThierry Strudel        goto download_cmplete;
9960ebd0bab066cd86d7a19f4646e0686dae885004eThierry Strudel    }
9970ebd0bab066cd86d7a19f4646e0686dae885004eThierry Strudel
9980ebd0bab066cd86d7a19f4646e0686dae885004eThierry Strudel    /* Do not download configuration if CRC passes */
9990ebd0bab066cd86d7a19f4646e0686dae885004eThierry Strudel    if (get_ath3k_crc(fd) < 0) {
10000ebd0bab066cd86d7a19f4646e0686dae885004eThierry Strudel        err = 0;
10010ebd0bab066cd86d7a19f4646e0686dae885004eThierry Strudel        goto download_cmplete;
10020ebd0bab066cd86d7a19f4646e0686dae885004eThierry Strudel    }
10030ebd0bab066cd86d7a19f4646e0686dae885004eThierry Strudel
10040ebd0bab066cd86d7a19f4646e0686dae885004eThierry Strudel    get_ps_file_name(dev_type, rom_version, ps_file);
10050ebd0bab066cd86d7a19f4646e0686dae885004eThierry Strudel    get_patch_file_name(dev_type, rom_version, build_version, patch_file);
10060ebd0bab066cd86d7a19f4646e0686dae885004eThierry Strudel
10070ebd0bab066cd86d7a19f4646e0686dae885004eThierry Strudel    stream = fopen(ps_file, "r");
10080ebd0bab066cd86d7a19f4646e0686dae885004eThierry Strudel    if (!stream) {
10090ebd0bab066cd86d7a19f4646e0686dae885004eThierry Strudel        ALOGI("firmware file open error:%s, ver:%x\n",ps_file, rom_version);
10100ebd0bab066cd86d7a19f4646e0686dae885004eThierry Strudel        if (rom_version == 0x1020201)
10110ebd0bab066cd86d7a19f4646e0686dae885004eThierry Strudel            err = 0;
10120ebd0bab066cd86d7a19f4646e0686dae885004eThierry Strudel        else
10130ebd0bab066cd86d7a19f4646e0686dae885004eThierry Strudel            err	= -EILSEQ;
10140ebd0bab066cd86d7a19f4646e0686dae885004eThierry Strudel        goto download_cmplete;
10150ebd0bab066cd86d7a19f4646e0686dae885004eThierry Strudel    }
10160ebd0bab066cd86d7a19f4646e0686dae885004eThierry Strudel    tag_count = ath_parse_ps(stream);
10170ebd0bab066cd86d7a19f4646e0686dae885004eThierry Strudel
10180ebd0bab066cd86d7a19f4646e0686dae885004eThierry Strudel    fclose(stream);
10190ebd0bab066cd86d7a19f4646e0686dae885004eThierry Strudel
10200ebd0bab066cd86d7a19f4646e0686dae885004eThierry Strudel    if (tag_count < 0) {
10210ebd0bab066cd86d7a19f4646e0686dae885004eThierry Strudel        err = -EILSEQ;
10220ebd0bab066cd86d7a19f4646e0686dae885004eThierry Strudel        goto download_cmplete;
10230ebd0bab066cd86d7a19f4646e0686dae885004eThierry Strudel    }
10240ebd0bab066cd86d7a19f4646e0686dae885004eThierry Strudel
10250ebd0bab066cd86d7a19f4646e0686dae885004eThierry Strudel    /*
10260ebd0bab066cd86d7a19f4646e0686dae885004eThierry Strudel    * It is not necessary that Patch file be available,
10270ebd0bab066cd86d7a19f4646e0686dae885004eThierry Strudel    * continue with PS Operations if patch file is not available.
10280ebd0bab066cd86d7a19f4646e0686dae885004eThierry Strudel    */
10290ebd0bab066cd86d7a19f4646e0686dae885004eThierry Strudel    if (patch_file[0] == '\0')
10300ebd0bab066cd86d7a19f4646e0686dae885004eThierry Strudel        err = 0;
10310ebd0bab066cd86d7a19f4646e0686dae885004eThierry Strudel
10320ebd0bab066cd86d7a19f4646e0686dae885004eThierry Strudel    stream = fopen(patch_file, "r");
10330ebd0bab066cd86d7a19f4646e0686dae885004eThierry Strudel    if (!stream)
10340ebd0bab066cd86d7a19f4646e0686dae885004eThierry Strudel        err = 0;
10350ebd0bab066cd86d7a19f4646e0686dae885004eThierry Strudel    else {
10360ebd0bab066cd86d7a19f4646e0686dae885004eThierry Strudel        patch_count = ps_patch_download(fd, stream);
10370ebd0bab066cd86d7a19f4646e0686dae885004eThierry Strudel        fclose(stream);
10380ebd0bab066cd86d7a19f4646e0686dae885004eThierry Strudel
10390ebd0bab066cd86d7a19f4646e0686dae885004eThierry Strudel        if (patch_count < 0) {
10400ebd0bab066cd86d7a19f4646e0686dae885004eThierry Strudel            err = -EILSEQ;
10410ebd0bab066cd86d7a19f4646e0686dae885004eThierry Strudel            goto download_cmplete;
10420ebd0bab066cd86d7a19f4646e0686dae885004eThierry Strudel        }
10430ebd0bab066cd86d7a19f4646e0686dae885004eThierry Strudel    }
10440ebd0bab066cd86d7a19f4646e0686dae885004eThierry Strudel
10450ebd0bab066cd86d7a19f4646e0686dae885004eThierry Strudel    err = ps_config_download(fd, tag_count);
10460ebd0bab066cd86d7a19f4646e0686dae885004eThierry Strudel
10470ebd0bab066cd86d7a19f4646e0686dae885004eThierry Strudeldownload_cmplete:
10480ebd0bab066cd86d7a19f4646e0686dae885004eThierry Strudel    if (!err)
10490ebd0bab066cd86d7a19f4646e0686dae885004eThierry Strudel        write_bdaddr_from_file(rom_version, fd);
10500ebd0bab066cd86d7a19f4646e0686dae885004eThierry Strudel
10510ebd0bab066cd86d7a19f4646e0686dae885004eThierry Strudel    return err;
10520ebd0bab066cd86d7a19f4646e0686dae885004eThierry Strudel}
10530ebd0bab066cd86d7a19f4646e0686dae885004eThierry Strudel
10540ebd0bab066cd86d7a19f4646e0686dae885004eThierry Strudelint ath3k_init(int fd, int speed, int init_speed, char *bdaddr, struct termios *ti)
10550ebd0bab066cd86d7a19f4646e0686dae885004eThierry Strudel{
10560ebd0bab066cd86d7a19f4646e0686dae885004eThierry Strudel    ALOGI(" %s ", __FUNCTION__);
10570ebd0bab066cd86d7a19f4646e0686dae885004eThierry Strudel
10580ebd0bab066cd86d7a19f4646e0686dae885004eThierry Strudel    int r;
10590ebd0bab066cd86d7a19f4646e0686dae885004eThierry Strudel    int err = 0;
10600ebd0bab066cd86d7a19f4646e0686dae885004eThierry Strudel    struct timespec tm = { 0, 500000};
10610ebd0bab066cd86d7a19f4646e0686dae885004eThierry Strudel    unsigned char cmd[MAX_CMD_LEN] = {0};
10620ebd0bab066cd86d7a19f4646e0686dae885004eThierry Strudel    unsigned char rsp[HCI_MAX_EVENT_SIZE];
10630ebd0bab066cd86d7a19f4646e0686dae885004eThierry Strudel    unsigned char *ptr = cmd + 1;
10640ebd0bab066cd86d7a19f4646e0686dae885004eThierry Strudel    hci_command_hdr *ch = (void *)ptr;
10650ebd0bab066cd86d7a19f4646e0686dae885004eThierry Strudel    int flags = 0;
10660ebd0bab066cd86d7a19f4646e0686dae885004eThierry Strudel
10670ebd0bab066cd86d7a19f4646e0686dae885004eThierry Strudel    if (ioctl(fd, TIOCMGET, &flags) < 0) {
10680ebd0bab066cd86d7a19f4646e0686dae885004eThierry Strudel        ALOGI("TIOCMGET failed in init\n");
10690ebd0bab066cd86d7a19f4646e0686dae885004eThierry Strudel        return -1;
10700ebd0bab066cd86d7a19f4646e0686dae885004eThierry Strudel    }
10710ebd0bab066cd86d7a19f4646e0686dae885004eThierry Strudel    flags |= TIOCM_RTS;
10720ebd0bab066cd86d7a19f4646e0686dae885004eThierry Strudel    if (ioctl(fd, TIOCMSET, &flags) < 0) {
10730ebd0bab066cd86d7a19f4646e0686dae885004eThierry Strudel        ALOGI("TIOCMSET failed in init: HW Flow-on error\n");
10740ebd0bab066cd86d7a19f4646e0686dae885004eThierry Strudel        return -1;
10750ebd0bab066cd86d7a19f4646e0686dae885004eThierry Strudel    }
10760ebd0bab066cd86d7a19f4646e0686dae885004eThierry Strudel
10770ebd0bab066cd86d7a19f4646e0686dae885004eThierry Strudel    /* set both controller and host baud rate to maximum possible value */
10780ebd0bab066cd86d7a19f4646e0686dae885004eThierry Strudel    err = set_cntrlr_baud(fd, speed);
10790ebd0bab066cd86d7a19f4646e0686dae885004eThierry Strudel    ALOGI("set_cntrlr_baud : ret:%d \n", err);
10800ebd0bab066cd86d7a19f4646e0686dae885004eThierry Strudel    if (err < 0)
10810ebd0bab066cd86d7a19f4646e0686dae885004eThierry Strudel        return err;
10820ebd0bab066cd86d7a19f4646e0686dae885004eThierry Strudel
10830ebd0bab066cd86d7a19f4646e0686dae885004eThierry Strudel    err = set_speed(fd, ti, speed);
10840ebd0bab066cd86d7a19f4646e0686dae885004eThierry Strudel    if (err < 0) {
10850ebd0bab066cd86d7a19f4646e0686dae885004eThierry Strudel        ALOGI("Can't set required baud rate");
10860ebd0bab066cd86d7a19f4646e0686dae885004eThierry Strudel        return err;
10870ebd0bab066cd86d7a19f4646e0686dae885004eThierry Strudel    }
10880ebd0bab066cd86d7a19f4646e0686dae885004eThierry Strudel
10890ebd0bab066cd86d7a19f4646e0686dae885004eThierry Strudel    /* Download PS and patch */
10900ebd0bab066cd86d7a19f4646e0686dae885004eThierry Strudel    r = ath_ps_download(fd);
10910ebd0bab066cd86d7a19f4646e0686dae885004eThierry Strudel    if (r < 0) {
10920ebd0bab066cd86d7a19f4646e0686dae885004eThierry Strudel        ALOGI("Failed to Download configuration");
10930ebd0bab066cd86d7a19f4646e0686dae885004eThierry Strudel        err = -ETIMEDOUT;
10940ebd0bab066cd86d7a19f4646e0686dae885004eThierry Strudel        goto failed;
10950ebd0bab066cd86d7a19f4646e0686dae885004eThierry Strudel    }
10960ebd0bab066cd86d7a19f4646e0686dae885004eThierry Strudel
10970ebd0bab066cd86d7a19f4646e0686dae885004eThierry Strudel    ALOGI("ath_ps_download is done\n");
10980ebd0bab066cd86d7a19f4646e0686dae885004eThierry Strudel
10990ebd0bab066cd86d7a19f4646e0686dae885004eThierry Strudel    cmd[0] = HCI_COMMAND_PKT;
11000ebd0bab066cd86d7a19f4646e0686dae885004eThierry Strudel    /* Write BDADDR */
11010ebd0bab066cd86d7a19f4646e0686dae885004eThierry Strudel    if (bdaddr) {
11020ebd0bab066cd86d7a19f4646e0686dae885004eThierry Strudel        ch->opcode = htobs(cmd_opcode_pack(HCI_VENDOR_CMD_OGF,
11030ebd0bab066cd86d7a19f4646e0686dae885004eThierry Strudel        HCI_PS_CMD_OCF));
11040ebd0bab066cd86d7a19f4646e0686dae885004eThierry Strudel        ch->plen = 10;
11050ebd0bab066cd86d7a19f4646e0686dae885004eThierry Strudel        ptr += HCI_COMMAND_HDR_SIZE;
11060ebd0bab066cd86d7a19f4646e0686dae885004eThierry Strudel
11070ebd0bab066cd86d7a19f4646e0686dae885004eThierry Strudel        ptr[0] = 0x01;
11080ebd0bab066cd86d7a19f4646e0686dae885004eThierry Strudel        ptr[1] = 0x01;
11090ebd0bab066cd86d7a19f4646e0686dae885004eThierry Strudel        ptr[2] = 0x00;
11100ebd0bab066cd86d7a19f4646e0686dae885004eThierry Strudel        ptr[3] = 0x06;
11110ebd0bab066cd86d7a19f4646e0686dae885004eThierry Strudel        str2ba(bdaddr, (bdaddr_t *)(ptr + 4));
11120ebd0bab066cd86d7a19f4646e0686dae885004eThierry Strudel
11130ebd0bab066cd86d7a19f4646e0686dae885004eThierry Strudel        if (write(fd, cmd, WRITE_BDADDR_CMD_LEN) !=
11140ebd0bab066cd86d7a19f4646e0686dae885004eThierry Strudel                WRITE_BDADDR_CMD_LEN) {
11150ebd0bab066cd86d7a19f4646e0686dae885004eThierry Strudel            ALOGI("Failed to write BD_ADDR command\n");
11160ebd0bab066cd86d7a19f4646e0686dae885004eThierry Strudel            err = -ETIMEDOUT;
11170ebd0bab066cd86d7a19f4646e0686dae885004eThierry Strudel            goto failed;
11180ebd0bab066cd86d7a19f4646e0686dae885004eThierry Strudel        }
11190ebd0bab066cd86d7a19f4646e0686dae885004eThierry Strudel
11200ebd0bab066cd86d7a19f4646e0686dae885004eThierry Strudel        if (read_hci_event(fd, rsp, sizeof(rsp)) < 0) {
11210ebd0bab066cd86d7a19f4646e0686dae885004eThierry Strudel            ALOGI("Failed to set BD_ADDR\n");
11220ebd0bab066cd86d7a19f4646e0686dae885004eThierry Strudel            err = -ETIMEDOUT;
11230ebd0bab066cd86d7a19f4646e0686dae885004eThierry Strudel            goto failed;
11240ebd0bab066cd86d7a19f4646e0686dae885004eThierry Strudel        }
11250ebd0bab066cd86d7a19f4646e0686dae885004eThierry Strudel    }
11260ebd0bab066cd86d7a19f4646e0686dae885004eThierry Strudel
11270ebd0bab066cd86d7a19f4646e0686dae885004eThierry Strudel    /* Send HCI Reset */
11280ebd0bab066cd86d7a19f4646e0686dae885004eThierry Strudel    cmd[1] = 0x03;
11290ebd0bab066cd86d7a19f4646e0686dae885004eThierry Strudel    cmd[2] = 0x0C;
11300ebd0bab066cd86d7a19f4646e0686dae885004eThierry Strudel    cmd[3] = 0x00;
11310ebd0bab066cd86d7a19f4646e0686dae885004eThierry Strudel
11320ebd0bab066cd86d7a19f4646e0686dae885004eThierry Strudel    r = write(fd, cmd, 4);
11330ebd0bab066cd86d7a19f4646e0686dae885004eThierry Strudel    if (r != 4) {
11340ebd0bab066cd86d7a19f4646e0686dae885004eThierry Strudel        err = -ETIMEDOUT;
11350ebd0bab066cd86d7a19f4646e0686dae885004eThierry Strudel        goto failed;
11360ebd0bab066cd86d7a19f4646e0686dae885004eThierry Strudel    }
11370ebd0bab066cd86d7a19f4646e0686dae885004eThierry Strudel
11380ebd0bab066cd86d7a19f4646e0686dae885004eThierry Strudel    nanosleep(&tm, NULL);
11390ebd0bab066cd86d7a19f4646e0686dae885004eThierry Strudel    if (read_hci_event(fd, rsp, sizeof(rsp)) < 0) {
11400ebd0bab066cd86d7a19f4646e0686dae885004eThierry Strudel        err = -ETIMEDOUT;
11410ebd0bab066cd86d7a19f4646e0686dae885004eThierry Strudel        goto failed;
11420ebd0bab066cd86d7a19f4646e0686dae885004eThierry Strudel    }
11430ebd0bab066cd86d7a19f4646e0686dae885004eThierry Strudel
11440ebd0bab066cd86d7a19f4646e0686dae885004eThierry Strudel    ALOGI("HCI Reset is done\n");
11450ebd0bab066cd86d7a19f4646e0686dae885004eThierry Strudel    err = set_cntrlr_baud(fd, speed);
11460ebd0bab066cd86d7a19f4646e0686dae885004eThierry Strudel    if (err < 0)
11470ebd0bab066cd86d7a19f4646e0686dae885004eThierry Strudel        ALOGI("set_cntrlr_baud0:%d,%d\n", speed, err);
11480ebd0bab066cd86d7a19f4646e0686dae885004eThierry Strudel
11490ebd0bab066cd86d7a19f4646e0686dae885004eThierry Strudelfailed:
11500ebd0bab066cd86d7a19f4646e0686dae885004eThierry Strudel    if (err < 0) {
11510ebd0bab066cd86d7a19f4646e0686dae885004eThierry Strudel        set_cntrlr_baud(fd, init_speed);
11520ebd0bab066cd86d7a19f4646e0686dae885004eThierry Strudel        set_speed(fd, ti, init_speed);
11530ebd0bab066cd86d7a19f4646e0686dae885004eThierry Strudel    }
11540ebd0bab066cd86d7a19f4646e0686dae885004eThierry Strudel
11550ebd0bab066cd86d7a19f4646e0686dae885004eThierry Strudel    return err;
11560ebd0bab066cd86d7a19f4646e0686dae885004eThierry Strudel
11570ebd0bab066cd86d7a19f4646e0686dae885004eThierry Strudel}
11580ebd0bab066cd86d7a19f4646e0686dae885004eThierry Strudel#define BTPROTO_HCI 1
11590ebd0bab066cd86d7a19f4646e0686dae885004eThierry Strudel
11600ebd0bab066cd86d7a19f4646e0686dae885004eThierry Strudel/* Open HCI device.
11610ebd0bab066cd86d7a19f4646e0686dae885004eThierry Strudel * Returns device descriptor (dd). */
11620ebd0bab066cd86d7a19f4646e0686dae885004eThierry Strudelint hci_open_dev(int dev_id)
11630ebd0bab066cd86d7a19f4646e0686dae885004eThierry Strudel{
11640ebd0bab066cd86d7a19f4646e0686dae885004eThierry Strudel    struct sockaddr_hci a;
11650ebd0bab066cd86d7a19f4646e0686dae885004eThierry Strudel    int dd, err;
11660ebd0bab066cd86d7a19f4646e0686dae885004eThierry Strudel
11670ebd0bab066cd86d7a19f4646e0686dae885004eThierry Strudel    /* Create HCI socket */
11680ebd0bab066cd86d7a19f4646e0686dae885004eThierry Strudel    dd = socket(AF_BLUETOOTH, SOCK_RAW, BTPROTO_HCI);
11690ebd0bab066cd86d7a19f4646e0686dae885004eThierry Strudel    if (dd < 0)
11700ebd0bab066cd86d7a19f4646e0686dae885004eThierry Strudel        return dd;
11710ebd0bab066cd86d7a19f4646e0686dae885004eThierry Strudel
11720ebd0bab066cd86d7a19f4646e0686dae885004eThierry Strudel    /* Bind socket to the HCI device */
11730ebd0bab066cd86d7a19f4646e0686dae885004eThierry Strudel    memset(&a, 0, sizeof(a));
11740ebd0bab066cd86d7a19f4646e0686dae885004eThierry Strudel    a.hci_family = AF_BLUETOOTH;
11750ebd0bab066cd86d7a19f4646e0686dae885004eThierry Strudel    a.hci_dev = dev_id;
11760ebd0bab066cd86d7a19f4646e0686dae885004eThierry Strudel    if (bind(dd, (struct sockaddr *) &a, sizeof(a)) < 0)
11770ebd0bab066cd86d7a19f4646e0686dae885004eThierry Strudel        goto failed;
11780ebd0bab066cd86d7a19f4646e0686dae885004eThierry Strudel
11790ebd0bab066cd86d7a19f4646e0686dae885004eThierry Strudel    return dd;
11800ebd0bab066cd86d7a19f4646e0686dae885004eThierry Strudel
11810ebd0bab066cd86d7a19f4646e0686dae885004eThierry Strudelfailed:
11820ebd0bab066cd86d7a19f4646e0686dae885004eThierry Strudel    err = errno;
11830ebd0bab066cd86d7a19f4646e0686dae885004eThierry Strudel    close(dd);
11840ebd0bab066cd86d7a19f4646e0686dae885004eThierry Strudel    errno = err;
11850ebd0bab066cd86d7a19f4646e0686dae885004eThierry Strudel
11860ebd0bab066cd86d7a19f4646e0686dae885004eThierry Strudel    return -1;
11870ebd0bab066cd86d7a19f4646e0686dae885004eThierry Strudel}
11880ebd0bab066cd86d7a19f4646e0686dae885004eThierry Strudel
11890ebd0bab066cd86d7a19f4646e0686dae885004eThierry Strudelint hci_close_dev(int dd)
11900ebd0bab066cd86d7a19f4646e0686dae885004eThierry Strudel{
11910ebd0bab066cd86d7a19f4646e0686dae885004eThierry Strudel    return close(dd);
11920ebd0bab066cd86d7a19f4646e0686dae885004eThierry Strudel}
11930ebd0bab066cd86d7a19f4646e0686dae885004eThierry Strudel
11940ebd0bab066cd86d7a19f4646e0686dae885004eThierry Strudel/* HCI functions that require open device
11950ebd0bab066cd86d7a19f4646e0686dae885004eThierry Strudel * dd - Device descriptor returned by hci_open_dev. */
11960ebd0bab066cd86d7a19f4646e0686dae885004eThierry Strudel
11970ebd0bab066cd86d7a19f4646e0686dae885004eThierry Strudelint hci_send_cmd(int dd, uint16_t ogf, uint16_t ocf, uint8_t plen, void *param)
11980ebd0bab066cd86d7a19f4646e0686dae885004eThierry Strudel{
11990ebd0bab066cd86d7a19f4646e0686dae885004eThierry Strudel    uint8_t type = HCI_COMMAND_PKT;
12000ebd0bab066cd86d7a19f4646e0686dae885004eThierry Strudel    hci_command_hdr hc;
12010ebd0bab066cd86d7a19f4646e0686dae885004eThierry Strudel    struct iovec iv[3];
12020ebd0bab066cd86d7a19f4646e0686dae885004eThierry Strudel    int ivn;
12030ebd0bab066cd86d7a19f4646e0686dae885004eThierry Strudel
12040ebd0bab066cd86d7a19f4646e0686dae885004eThierry Strudel    hc.opcode = htobs(cmd_opcode_pack(ogf, ocf));
12050ebd0bab066cd86d7a19f4646e0686dae885004eThierry Strudel    hc.plen= plen;
12060ebd0bab066cd86d7a19f4646e0686dae885004eThierry Strudel
12070ebd0bab066cd86d7a19f4646e0686dae885004eThierry Strudel    iv[0].iov_base = &type;
12080ebd0bab066cd86d7a19f4646e0686dae885004eThierry Strudel    iv[0].iov_len  = 1;
12090ebd0bab066cd86d7a19f4646e0686dae885004eThierry Strudel    iv[1].iov_base = &hc;
12100ebd0bab066cd86d7a19f4646e0686dae885004eThierry Strudel    iv[1].iov_len  = HCI_COMMAND_HDR_SIZE;
12110ebd0bab066cd86d7a19f4646e0686dae885004eThierry Strudel    ivn = 2;
12120ebd0bab066cd86d7a19f4646e0686dae885004eThierry Strudel
12130ebd0bab066cd86d7a19f4646e0686dae885004eThierry Strudel    if (plen) {
12140ebd0bab066cd86d7a19f4646e0686dae885004eThierry Strudel        iv[2].iov_base = param;
12150ebd0bab066cd86d7a19f4646e0686dae885004eThierry Strudel        iv[2].iov_len  = plen;
12160ebd0bab066cd86d7a19f4646e0686dae885004eThierry Strudel        ivn = 3;
12170ebd0bab066cd86d7a19f4646e0686dae885004eThierry Strudel    }
12180ebd0bab066cd86d7a19f4646e0686dae885004eThierry Strudel
12190ebd0bab066cd86d7a19f4646e0686dae885004eThierry Strudel    while (writev(dd, iv, ivn) < 0) {
12200ebd0bab066cd86d7a19f4646e0686dae885004eThierry Strudel        if (errno == EAGAIN || errno == EINTR)
12210ebd0bab066cd86d7a19f4646e0686dae885004eThierry Strudel            continue;
12220ebd0bab066cd86d7a19f4646e0686dae885004eThierry Strudel        return -1;
12230ebd0bab066cd86d7a19f4646e0686dae885004eThierry Strudel    }
12240ebd0bab066cd86d7a19f4646e0686dae885004eThierry Strudel    return 0;
12250ebd0bab066cd86d7a19f4646e0686dae885004eThierry Strudel}
12260ebd0bab066cd86d7a19f4646e0686dae885004eThierry Strudel
12270ebd0bab066cd86d7a19f4646e0686dae885004eThierry Strudel#define HCI_SLEEP_CMD_OCF     0x04
12280ebd0bab066cd86d7a19f4646e0686dae885004eThierry Strudel#define TIOCSETD 0x5423
12290ebd0bab066cd86d7a19f4646e0686dae885004eThierry Strudel#define HCIUARTSETFLAGS _IOW('U', 204, int)
12300ebd0bab066cd86d7a19f4646e0686dae885004eThierry Strudel#define HCIUARTSETPROTO _IOW('U', 200, int)
12310ebd0bab066cd86d7a19f4646e0686dae885004eThierry Strudel#define HCIUARTGETDEVICE _IOW('U', 202, int)
12320ebd0bab066cd86d7a19f4646e0686dae885004eThierry Strudel/*
12330ebd0bab066cd86d7a19f4646e0686dae885004eThierry Strudel * Atheros AR300x specific initialization post callback
12340ebd0bab066cd86d7a19f4646e0686dae885004eThierry Strudel */
12350ebd0bab066cd86d7a19f4646e0686dae885004eThierry Strudelint ath3k_post(int fd, int pm)
12360ebd0bab066cd86d7a19f4646e0686dae885004eThierry Strudel{
12370ebd0bab066cd86d7a19f4646e0686dae885004eThierry Strudel    int dev_id, dd;
12380ebd0bab066cd86d7a19f4646e0686dae885004eThierry Strudel    struct timespec tm = { 0, 50000};
12390ebd0bab066cd86d7a19f4646e0686dae885004eThierry Strudel
12400ebd0bab066cd86d7a19f4646e0686dae885004eThierry Strudel    sleep(1);
12410ebd0bab066cd86d7a19f4646e0686dae885004eThierry Strudel
12420ebd0bab066cd86d7a19f4646e0686dae885004eThierry Strudel    dev_id = ioctl(fd, HCIUARTGETDEVICE, 0);
12430ebd0bab066cd86d7a19f4646e0686dae885004eThierry Strudel    if (dev_id < 0) {
12440ebd0bab066cd86d7a19f4646e0686dae885004eThierry Strudel        perror("cannot get device id");
12450ebd0bab066cd86d7a19f4646e0686dae885004eThierry Strudel        return dev_id;
12460ebd0bab066cd86d7a19f4646e0686dae885004eThierry Strudel    }
12470ebd0bab066cd86d7a19f4646e0686dae885004eThierry Strudel
12480ebd0bab066cd86d7a19f4646e0686dae885004eThierry Strudel    dd = hci_open_dev(dev_id);
12490ebd0bab066cd86d7a19f4646e0686dae885004eThierry Strudel    if (dd < 0) {
12500ebd0bab066cd86d7a19f4646e0686dae885004eThierry Strudel        perror("HCI device open failed");
12510ebd0bab066cd86d7a19f4646e0686dae885004eThierry Strudel        return dd;
12520ebd0bab066cd86d7a19f4646e0686dae885004eThierry Strudel    }
12530ebd0bab066cd86d7a19f4646e0686dae885004eThierry Strudel
12540ebd0bab066cd86d7a19f4646e0686dae885004eThierry Strudel    if (ioctl(dd, HCIDEVUP, dev_id) < 0 && errno != EALREADY) {
12550ebd0bab066cd86d7a19f4646e0686dae885004eThierry Strudel        perror("hci down:Power management Disabled");
12560ebd0bab066cd86d7a19f4646e0686dae885004eThierry Strudel        hci_close_dev(dd);
12570ebd0bab066cd86d7a19f4646e0686dae885004eThierry Strudel        return -1;
12580ebd0bab066cd86d7a19f4646e0686dae885004eThierry Strudel    }
12590ebd0bab066cd86d7a19f4646e0686dae885004eThierry Strudel
12600ebd0bab066cd86d7a19f4646e0686dae885004eThierry Strudel    /* send vendor specific command with Sleep feature Enabled */
12610ebd0bab066cd86d7a19f4646e0686dae885004eThierry Strudel    if (hci_send_cmd(dd, OGF_VENDOR_CMD, HCI_SLEEP_CMD_OCF, 1, &pm) < 0)
12620ebd0bab066cd86d7a19f4646e0686dae885004eThierry Strudel        perror("PM command failed, power management Disabled");
12630ebd0bab066cd86d7a19f4646e0686dae885004eThierry Strudel
12640ebd0bab066cd86d7a19f4646e0686dae885004eThierry Strudel    nanosleep(&tm, NULL);
12650ebd0bab066cd86d7a19f4646e0686dae885004eThierry Strudel    hci_close_dev(dd);
12660ebd0bab066cd86d7a19f4646e0686dae885004eThierry Strudel
12670ebd0bab066cd86d7a19f4646e0686dae885004eThierry Strudel    return 0;
12680ebd0bab066cd86d7a19f4646e0686dae885004eThierry Strudel}
12690ebd0bab066cd86d7a19f4646e0686dae885004eThierry Strudel
12700ebd0bab066cd86d7a19f4646e0686dae885004eThierry Strudel
12710ebd0bab066cd86d7a19f4646e0686dae885004eThierry Strudel
12720ebd0bab066cd86d7a19f4646e0686dae885004eThierry Strudel#define FLOW_CTL    0x0001
12730ebd0bab066cd86d7a19f4646e0686dae885004eThierry Strudel#define ENABLE_PM   1
12740ebd0bab066cd86d7a19f4646e0686dae885004eThierry Strudel#define DISABLE_PM  0
12750ebd0bab066cd86d7a19f4646e0686dae885004eThierry Strudel
12760ebd0bab066cd86d7a19f4646e0686dae885004eThierry Strudel/* Initialize UART driver */
12770ebd0bab066cd86d7a19f4646e0686dae885004eThierry Strudelstatic int init_uart(char *dev, struct uart_t *u, int send_break, int raw)
12780ebd0bab066cd86d7a19f4646e0686dae885004eThierry Strudel{
12790ebd0bab066cd86d7a19f4646e0686dae885004eThierry Strudel    ALOGI(" %s ", __FUNCTION__);
12800ebd0bab066cd86d7a19f4646e0686dae885004eThierry Strudel
12810ebd0bab066cd86d7a19f4646e0686dae885004eThierry Strudel    struct termios ti;
12820ebd0bab066cd86d7a19f4646e0686dae885004eThierry Strudel
12830ebd0bab066cd86d7a19f4646e0686dae885004eThierry Strudel    int i, fd;
12840ebd0bab066cd86d7a19f4646e0686dae885004eThierry Strudel    unsigned long flags = 0;
12850ebd0bab066cd86d7a19f4646e0686dae885004eThierry Strudel
12860ebd0bab066cd86d7a19f4646e0686dae885004eThierry Strudel    if (raw)
12870ebd0bab066cd86d7a19f4646e0686dae885004eThierry Strudel        flags |= 1 << HCI_UART_RAW_DEVICE;
12880ebd0bab066cd86d7a19f4646e0686dae885004eThierry Strudel
12890ebd0bab066cd86d7a19f4646e0686dae885004eThierry Strudel
12900ebd0bab066cd86d7a19f4646e0686dae885004eThierry Strudel    fd = open(dev, O_RDWR | O_NOCTTY);
12910ebd0bab066cd86d7a19f4646e0686dae885004eThierry Strudel
12920ebd0bab066cd86d7a19f4646e0686dae885004eThierry Strudel    if (fd < 0) {
12930ebd0bab066cd86d7a19f4646e0686dae885004eThierry Strudel        ALOGI("Can't open serial port");
12940ebd0bab066cd86d7a19f4646e0686dae885004eThierry Strudel        return -1;
12950ebd0bab066cd86d7a19f4646e0686dae885004eThierry Strudel    }
12960ebd0bab066cd86d7a19f4646e0686dae885004eThierry Strudel
12970ebd0bab066cd86d7a19f4646e0686dae885004eThierry Strudel
12980ebd0bab066cd86d7a19f4646e0686dae885004eThierry Strudel    tcflush(fd, TCIOFLUSH);
12990ebd0bab066cd86d7a19f4646e0686dae885004eThierry Strudel
13000ebd0bab066cd86d7a19f4646e0686dae885004eThierry Strudel    if (tcgetattr(fd, &ti) < 0) {
13010ebd0bab066cd86d7a19f4646e0686dae885004eThierry Strudel        ALOGI("Can't get port settings: %d\n", errno);
13020ebd0bab066cd86d7a19f4646e0686dae885004eThierry Strudel        return -1;
13030ebd0bab066cd86d7a19f4646e0686dae885004eThierry Strudel    }
13040ebd0bab066cd86d7a19f4646e0686dae885004eThierry Strudel
13050ebd0bab066cd86d7a19f4646e0686dae885004eThierry Strudel    cfmakeraw(&ti);
13060ebd0bab066cd86d7a19f4646e0686dae885004eThierry Strudel
13070ebd0bab066cd86d7a19f4646e0686dae885004eThierry Strudel    ti.c_cflag |= CLOCAL;
13080ebd0bab066cd86d7a19f4646e0686dae885004eThierry Strudel    if (u->flags & FLOW_CTL)
13090ebd0bab066cd86d7a19f4646e0686dae885004eThierry Strudel        ti.c_cflag |= CRTSCTS;
13100ebd0bab066cd86d7a19f4646e0686dae885004eThierry Strudel    else
13110ebd0bab066cd86d7a19f4646e0686dae885004eThierry Strudel        ti.c_cflag &= ~CRTSCTS;
13120ebd0bab066cd86d7a19f4646e0686dae885004eThierry Strudel
13130ebd0bab066cd86d7a19f4646e0686dae885004eThierry Strudel    if (tcsetattr(fd, TCSANOW, &ti) < 0) {
13140ebd0bab066cd86d7a19f4646e0686dae885004eThierry Strudel        ALOGI("Can't set port settings");
13150ebd0bab066cd86d7a19f4646e0686dae885004eThierry Strudel        return -1;
13160ebd0bab066cd86d7a19f4646e0686dae885004eThierry Strudel    }
13170ebd0bab066cd86d7a19f4646e0686dae885004eThierry Strudel
13180ebd0bab066cd86d7a19f4646e0686dae885004eThierry Strudel    if (set_speed(fd, &ti, u->init_speed) < 0) {
13190ebd0bab066cd86d7a19f4646e0686dae885004eThierry Strudel        ALOGI("Can't set initial baud rate");
13200ebd0bab066cd86d7a19f4646e0686dae885004eThierry Strudel        return -1;
13210ebd0bab066cd86d7a19f4646e0686dae885004eThierry Strudel    }
13220ebd0bab066cd86d7a19f4646e0686dae885004eThierry Strudel
13230ebd0bab066cd86d7a19f4646e0686dae885004eThierry Strudel    tcflush(fd, TCIOFLUSH);
13240ebd0bab066cd86d7a19f4646e0686dae885004eThierry Strudel
13250ebd0bab066cd86d7a19f4646e0686dae885004eThierry Strudel    if (send_break) {
13260ebd0bab066cd86d7a19f4646e0686dae885004eThierry Strudel        tcsendbreak(fd, 0);
13270ebd0bab066cd86d7a19f4646e0686dae885004eThierry Strudel        usleep(500000);
13280ebd0bab066cd86d7a19f4646e0686dae885004eThierry Strudel    }
13290ebd0bab066cd86d7a19f4646e0686dae885004eThierry Strudel
13300ebd0bab066cd86d7a19f4646e0686dae885004eThierry Strudel    ath3k_init(fd,u->speed,u->init_speed,u->bdaddr, &ti);
13310ebd0bab066cd86d7a19f4646e0686dae885004eThierry Strudel
13320ebd0bab066cd86d7a19f4646e0686dae885004eThierry Strudel    ALOGI("Device setup complete\n");
13330ebd0bab066cd86d7a19f4646e0686dae885004eThierry Strudel
13340ebd0bab066cd86d7a19f4646e0686dae885004eThierry Strudel
13350ebd0bab066cd86d7a19f4646e0686dae885004eThierry Strudel    tcflush(fd, TCIOFLUSH);
13360ebd0bab066cd86d7a19f4646e0686dae885004eThierry Strudel
13370ebd0bab066cd86d7a19f4646e0686dae885004eThierry Strudel    // Set actual baudrate
13380ebd0bab066cd86d7a19f4646e0686dae885004eThierry Strudel    /*
13390ebd0bab066cd86d7a19f4646e0686dae885004eThierry Strudel    if (set_speed(fd, &ti, u->speed) < 0) {
13400ebd0bab066cd86d7a19f4646e0686dae885004eThierry Strudel        perror("Can't set baud rate");
13410ebd0bab066cd86d7a19f4646e0686dae885004eThierry Strudel        return -1;
13420ebd0bab066cd86d7a19f4646e0686dae885004eThierry Strudel    }
13430ebd0bab066cd86d7a19f4646e0686dae885004eThierry Strudel
13440ebd0bab066cd86d7a19f4646e0686dae885004eThierry Strudel    i = N_HCI;
13450ebd0bab066cd86d7a19f4646e0686dae885004eThierry Strudel    if (ioctl(fd, TIOCSETD, &i) < 0) {
13460ebd0bab066cd86d7a19f4646e0686dae885004eThierry Strudel        perror("Can't set line discipline");
13470ebd0bab066cd86d7a19f4646e0686dae885004eThierry Strudel        return -1;
13480ebd0bab066cd86d7a19f4646e0686dae885004eThierry Strudel    }
13490ebd0bab066cd86d7a19f4646e0686dae885004eThierry Strudel
13500ebd0bab066cd86d7a19f4646e0686dae885004eThierry Strudel    if (flags && ioctl(fd, HCIUARTSETFLAGS, flags) < 0) {
13510ebd0bab066cd86d7a19f4646e0686dae885004eThierry Strudel        perror("Can't set UART flags");
13520ebd0bab066cd86d7a19f4646e0686dae885004eThierry Strudel        return -1;
13530ebd0bab066cd86d7a19f4646e0686dae885004eThierry Strudel    }
13540ebd0bab066cd86d7a19f4646e0686dae885004eThierry Strudel
13550ebd0bab066cd86d7a19f4646e0686dae885004eThierry Strudel    if (ioctl(fd, HCIUARTSETPROTO, u->proto) < 0) {
13560ebd0bab066cd86d7a19f4646e0686dae885004eThierry Strudel        perror("Can't set device");
13570ebd0bab066cd86d7a19f4646e0686dae885004eThierry Strudel        return -1;
13580ebd0bab066cd86d7a19f4646e0686dae885004eThierry Strudel    }
13590ebd0bab066cd86d7a19f4646e0686dae885004eThierry Strudel
13600ebd0bab066cd86d7a19f4646e0686dae885004eThierry Strudel#if !defined(SW_BOARD_HAVE_BLUETOOTH_RTK)
13610ebd0bab066cd86d7a19f4646e0686dae885004eThierry Strudel    ath3k_post(fd, u->pm);
13620ebd0bab066cd86d7a19f4646e0686dae885004eThierry Strudel#endif
13630ebd0bab066cd86d7a19f4646e0686dae885004eThierry Strudel    */
13640ebd0bab066cd86d7a19f4646e0686dae885004eThierry Strudel
13650ebd0bab066cd86d7a19f4646e0686dae885004eThierry Strudel    return fd;
13660ebd0bab066cd86d7a19f4646e0686dae885004eThierry Strudel}
13670ebd0bab066cd86d7a19f4646e0686dae885004eThierry Strudel
13680ebd0bab066cd86d7a19f4646e0686dae885004eThierry Strudel
13690ebd0bab066cd86d7a19f4646e0686dae885004eThierry Strudelint hw_config_ath3k(char *port_name)
13700ebd0bab066cd86d7a19f4646e0686dae885004eThierry Strudel{
13710ebd0bab066cd86d7a19f4646e0686dae885004eThierry Strudel    ALOGI(" %s ", __FUNCTION__);
13720ebd0bab066cd86d7a19f4646e0686dae885004eThierry Strudel    PSCounter=0;
13730ebd0bab066cd86d7a19f4646e0686dae885004eThierry Strudel    struct sigaction sa;
13740ebd0bab066cd86d7a19f4646e0686dae885004eThierry Strudel    struct uart_t u ;
13750ebd0bab066cd86d7a19f4646e0686dae885004eThierry Strudel    int n=0,send_break=0,raw=0;
13760ebd0bab066cd86d7a19f4646e0686dae885004eThierry Strudel
13770ebd0bab066cd86d7a19f4646e0686dae885004eThierry Strudel    memset(&u, 0, sizeof(u));
13780ebd0bab066cd86d7a19f4646e0686dae885004eThierry Strudel    u.speed =3000000;
13790ebd0bab066cd86d7a19f4646e0686dae885004eThierry Strudel    u.init_speed =115200;
13800ebd0bab066cd86d7a19f4646e0686dae885004eThierry Strudel    u.flags |= FLOW_CTL;
13810ebd0bab066cd86d7a19f4646e0686dae885004eThierry Strudel    u.pm = DISABLE_PM;
13820ebd0bab066cd86d7a19f4646e0686dae885004eThierry Strudel
13830ebd0bab066cd86d7a19f4646e0686dae885004eThierry Strudel    n = init_uart(port_name, &u, send_break, raw);
13840ebd0bab066cd86d7a19f4646e0686dae885004eThierry Strudel    if (n < 0) {
13850ebd0bab066cd86d7a19f4646e0686dae885004eThierry Strudel        ALOGI("Can't initialize device");
13860ebd0bab066cd86d7a19f4646e0686dae885004eThierry Strudel    }
13870ebd0bab066cd86d7a19f4646e0686dae885004eThierry Strudel
13880ebd0bab066cd86d7a19f4646e0686dae885004eThierry Strudel    return n;
13890ebd0bab066cd86d7a19f4646e0686dae885004eThierry Strudel}
13900ebd0bab066cd86d7a19f4646e0686dae885004eThierry Strudel
13910ebd0bab066cd86d7a19f4646e0686dae885004eThierry Strudelvoid lpm_set_ar3k(uint8_t pio, uint8_t action, uint8_t polarity)
13920ebd0bab066cd86d7a19f4646e0686dae885004eThierry Strudel{
13930ebd0bab066cd86d7a19f4646e0686dae885004eThierry Strudel    int rc;
13940ebd0bab066cd86d7a19f4646e0686dae885004eThierry Strudel    int fd = -1;
13950ebd0bab066cd86d7a19f4646e0686dae885004eThierry Strudel    char buffer;
13960ebd0bab066cd86d7a19f4646e0686dae885004eThierry Strudel
13970ebd0bab066cd86d7a19f4646e0686dae885004eThierry Strudel    ALOGI("lpm mode: %d  action: %d", pio, action);
13980ebd0bab066cd86d7a19f4646e0686dae885004eThierry Strudel
13990ebd0bab066cd86d7a19f4646e0686dae885004eThierry Strudel    RESERVED(polarity);
14000ebd0bab066cd86d7a19f4646e0686dae885004eThierry Strudel
14010ebd0bab066cd86d7a19f4646e0686dae885004eThierry Strudel    switch (pio)
14020ebd0bab066cd86d7a19f4646e0686dae885004eThierry Strudel    {
14030ebd0bab066cd86d7a19f4646e0686dae885004eThierry Strudel        case UPIO_LPM_MODE:
14040ebd0bab066cd86d7a19f4646e0686dae885004eThierry Strudel            if (upio_state[UPIO_LPM_MODE] == action)
14050ebd0bab066cd86d7a19f4646e0686dae885004eThierry Strudel            {
14060ebd0bab066cd86d7a19f4646e0686dae885004eThierry Strudel                ALOGI("LPM is %s already", lpm_mode[action]);
14070ebd0bab066cd86d7a19f4646e0686dae885004eThierry Strudel                return;
14080ebd0bab066cd86d7a19f4646e0686dae885004eThierry Strudel            }
14090ebd0bab066cd86d7a19f4646e0686dae885004eThierry Strudel
14100ebd0bab066cd86d7a19f4646e0686dae885004eThierry Strudel            fd = open(VENDOR_LPM_PROC_NODE, O_WRONLY);
14110ebd0bab066cd86d7a19f4646e0686dae885004eThierry Strudel
14120ebd0bab066cd86d7a19f4646e0686dae885004eThierry Strudel            if (fd < 0)
14130ebd0bab066cd86d7a19f4646e0686dae885004eThierry Strudel            {
14140ebd0bab066cd86d7a19f4646e0686dae885004eThierry Strudel                ALOGE("upio_set : open(%s) for write failed: %s (%d)",
14150ebd0bab066cd86d7a19f4646e0686dae885004eThierry Strudel                VENDOR_LPM_PROC_NODE, strerror(errno), errno);
14160ebd0bab066cd86d7a19f4646e0686dae885004eThierry Strudel                return;
14170ebd0bab066cd86d7a19f4646e0686dae885004eThierry Strudel            }
14180ebd0bab066cd86d7a19f4646e0686dae885004eThierry Strudel
14190ebd0bab066cd86d7a19f4646e0686dae885004eThierry Strudel            if (action == UPIO_ASSERT)
14200ebd0bab066cd86d7a19f4646e0686dae885004eThierry Strudel            {
14210ebd0bab066cd86d7a19f4646e0686dae885004eThierry Strudel                buffer = '1';
14220ebd0bab066cd86d7a19f4646e0686dae885004eThierry Strudel            }
14230ebd0bab066cd86d7a19f4646e0686dae885004eThierry Strudel            else
14240ebd0bab066cd86d7a19f4646e0686dae885004eThierry Strudel            {
14250ebd0bab066cd86d7a19f4646e0686dae885004eThierry Strudel                buffer = '0';
14260ebd0bab066cd86d7a19f4646e0686dae885004eThierry Strudel            }
14270ebd0bab066cd86d7a19f4646e0686dae885004eThierry Strudel
14280ebd0bab066cd86d7a19f4646e0686dae885004eThierry Strudel            if (write(fd, &buffer, 1) < 0)
14290ebd0bab066cd86d7a19f4646e0686dae885004eThierry Strudel            {
14300ebd0bab066cd86d7a19f4646e0686dae885004eThierry Strudel                ALOGE("upio_set : write(%s) failed: %s (%d)",
14310ebd0bab066cd86d7a19f4646e0686dae885004eThierry Strudel                VENDOR_LPM_PROC_NODE, strerror(errno),errno);
14320ebd0bab066cd86d7a19f4646e0686dae885004eThierry Strudel            }
14330ebd0bab066cd86d7a19f4646e0686dae885004eThierry Strudel            else
14340ebd0bab066cd86d7a19f4646e0686dae885004eThierry Strudel            {
14350ebd0bab066cd86d7a19f4646e0686dae885004eThierry Strudel                upio_state[UPIO_LPM_MODE] = action;
14360ebd0bab066cd86d7a19f4646e0686dae885004eThierry Strudel                ALOGI("LPM is set to %s", lpm_mode[action]);
14370ebd0bab066cd86d7a19f4646e0686dae885004eThierry Strudel            }
14380ebd0bab066cd86d7a19f4646e0686dae885004eThierry Strudel
14390ebd0bab066cd86d7a19f4646e0686dae885004eThierry Strudel            if (fd >= 0)
14400ebd0bab066cd86d7a19f4646e0686dae885004eThierry Strudel                close(fd);
14410ebd0bab066cd86d7a19f4646e0686dae885004eThierry Strudel
14420ebd0bab066cd86d7a19f4646e0686dae885004eThierry Strudel            break;
14430ebd0bab066cd86d7a19f4646e0686dae885004eThierry Strudel
14440ebd0bab066cd86d7a19f4646e0686dae885004eThierry Strudel        case UPIO_BT_WAKE:
14450ebd0bab066cd86d7a19f4646e0686dae885004eThierry Strudel            /* UPIO_DEASSERT should be allowed because in Rx case assert occur
14460ebd0bab066cd86d7a19f4646e0686dae885004eThierry Strudel            * from the remote side where as deassert  will be initiated from Host
14470ebd0bab066cd86d7a19f4646e0686dae885004eThierry Strudel            */
14480ebd0bab066cd86d7a19f4646e0686dae885004eThierry Strudel            if ((action == UPIO_ASSERT) && (upio_state[UPIO_BT_WAKE] == action))
14490ebd0bab066cd86d7a19f4646e0686dae885004eThierry Strudel            {
14500ebd0bab066cd86d7a19f4646e0686dae885004eThierry Strudel                ALOGI("BT_WAKE is %s already", lpm_state[action]);
14510ebd0bab066cd86d7a19f4646e0686dae885004eThierry Strudel
14520ebd0bab066cd86d7a19f4646e0686dae885004eThierry Strudel                return;
14530ebd0bab066cd86d7a19f4646e0686dae885004eThierry Strudel            }
14540ebd0bab066cd86d7a19f4646e0686dae885004eThierry Strudel
14550ebd0bab066cd86d7a19f4646e0686dae885004eThierry Strudel            if (action == UPIO_DEASSERT)
14560ebd0bab066cd86d7a19f4646e0686dae885004eThierry Strudel                buffer = '0';
14570ebd0bab066cd86d7a19f4646e0686dae885004eThierry Strudel            else
14580ebd0bab066cd86d7a19f4646e0686dae885004eThierry Strudel                buffer = '1';
14590ebd0bab066cd86d7a19f4646e0686dae885004eThierry Strudel
14600ebd0bab066cd86d7a19f4646e0686dae885004eThierry Strudel            fd = open(VENDOR_BTWRITE_PROC_NODE, O_WRONLY);
14610ebd0bab066cd86d7a19f4646e0686dae885004eThierry Strudel
14620ebd0bab066cd86d7a19f4646e0686dae885004eThierry Strudel            if (fd < 0)
14630ebd0bab066cd86d7a19f4646e0686dae885004eThierry Strudel            {
14640ebd0bab066cd86d7a19f4646e0686dae885004eThierry Strudel                ALOGE("upio_set : open(%s) for write failed: %s (%d)",
14650ebd0bab066cd86d7a19f4646e0686dae885004eThierry Strudel                VENDOR_BTWRITE_PROC_NODE, strerror(errno), errno);
14660ebd0bab066cd86d7a19f4646e0686dae885004eThierry Strudel                return;
14670ebd0bab066cd86d7a19f4646e0686dae885004eThierry Strudel            }
14680ebd0bab066cd86d7a19f4646e0686dae885004eThierry Strudel
14690ebd0bab066cd86d7a19f4646e0686dae885004eThierry Strudel            if (write(fd, &buffer, 1) < 0)
14700ebd0bab066cd86d7a19f4646e0686dae885004eThierry Strudel            {
14710ebd0bab066cd86d7a19f4646e0686dae885004eThierry Strudel                ALOGE("upio_set : write(%s) failed: %s (%d)",
14720ebd0bab066cd86d7a19f4646e0686dae885004eThierry Strudel                VENDOR_BTWRITE_PROC_NODE, strerror(errno),errno);
14730ebd0bab066cd86d7a19f4646e0686dae885004eThierry Strudel            }
14740ebd0bab066cd86d7a19f4646e0686dae885004eThierry Strudel            else
14750ebd0bab066cd86d7a19f4646e0686dae885004eThierry Strudel            {
14760ebd0bab066cd86d7a19f4646e0686dae885004eThierry Strudel                upio_state[UPIO_BT_WAKE] = action;
14770ebd0bab066cd86d7a19f4646e0686dae885004eThierry Strudel                ALOGI("BT_WAKE is set to %s", lpm_state[action]);
14780ebd0bab066cd86d7a19f4646e0686dae885004eThierry Strudel            }
14790ebd0bab066cd86d7a19f4646e0686dae885004eThierry Strudel
14800ebd0bab066cd86d7a19f4646e0686dae885004eThierry Strudel            ALOGI("proc btwrite assertion");
14810ebd0bab066cd86d7a19f4646e0686dae885004eThierry Strudel
14820ebd0bab066cd86d7a19f4646e0686dae885004eThierry Strudel            if (fd >= 0)
14830ebd0bab066cd86d7a19f4646e0686dae885004eThierry Strudel                close(fd);
14840ebd0bab066cd86d7a19f4646e0686dae885004eThierry Strudel
14850ebd0bab066cd86d7a19f4646e0686dae885004eThierry Strudel            break;
14860ebd0bab066cd86d7a19f4646e0686dae885004eThierry Strudel
14870ebd0bab066cd86d7a19f4646e0686dae885004eThierry Strudel        case UPIO_HOST_WAKE:
14880ebd0bab066cd86d7a19f4646e0686dae885004eThierry Strudel            ALOGI("upio_set: UPIO_HOST_WAKE");
14890ebd0bab066cd86d7a19f4646e0686dae885004eThierry Strudel            break;
14900ebd0bab066cd86d7a19f4646e0686dae885004eThierry Strudel    }
14910ebd0bab066cd86d7a19f4646e0686dae885004eThierry Strudel
14920ebd0bab066cd86d7a19f4646e0686dae885004eThierry Strudel}
1493