1635682da6daf370cdba78511b917e166f0b6dbecSteve Pfetsch/*
2635682da6daf370cdba78511b917e166f0b6dbecSteve Pfetsch *
3635682da6daf370cdba78511b917e166f0b6dbecSteve Pfetsch *  Copyright (c) 2013, The Linux Foundation. All rights reserved.
4635682da6daf370cdba78511b917e166f0b6dbecSteve Pfetsch *  Not a Contribution.
5635682da6daf370cdba78511b917e166f0b6dbecSteve Pfetsch *
6635682da6daf370cdba78511b917e166f0b6dbecSteve Pfetsch *  Copyright 2012 The Android Open Source Project
7635682da6daf370cdba78511b917e166f0b6dbecSteve Pfetsch *
8635682da6daf370cdba78511b917e166f0b6dbecSteve Pfetsch *  Licensed under the Apache License, Version 2.0 (the "License"); you
9635682da6daf370cdba78511b917e166f0b6dbecSteve Pfetsch *  may not use this file except in compliance with the License. You may
10635682da6daf370cdba78511b917e166f0b6dbecSteve Pfetsch *  obtain a copy of the License at
11635682da6daf370cdba78511b917e166f0b6dbecSteve Pfetsch *
12635682da6daf370cdba78511b917e166f0b6dbecSteve Pfetsch *  http://www.apache.org/licenses/LICENSE-2.0
13635682da6daf370cdba78511b917e166f0b6dbecSteve Pfetsch *
14635682da6daf370cdba78511b917e166f0b6dbecSteve Pfetsch *  Unless required by applicable law or agreed to in writing, software
15635682da6daf370cdba78511b917e166f0b6dbecSteve Pfetsch *  distributed under the License is distributed on an "AS IS" BASIS,
16635682da6daf370cdba78511b917e166f0b6dbecSteve Pfetsch *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
17635682da6daf370cdba78511b917e166f0b6dbecSteve Pfetsch *  implied. See the License for the specific language governing
18635682da6daf370cdba78511b917e166f0b6dbecSteve Pfetsch *  permissions and limitations under the License.
19635682da6daf370cdba78511b917e166f0b6dbecSteve Pfetsch *
20635682da6daf370cdba78511b917e166f0b6dbecSteve Pfetsch */
21635682da6daf370cdba78511b917e166f0b6dbecSteve Pfetsch
22635682da6daf370cdba78511b917e166f0b6dbecSteve Pfetsch/******************************************************************************
23635682da6daf370cdba78511b917e166f0b6dbecSteve Pfetsch *
24635682da6daf370cdba78511b917e166f0b6dbecSteve Pfetsch *  Filename:      hw_ar3k.c
25635682da6daf370cdba78511b917e166f0b6dbecSteve Pfetsch *
26635682da6daf370cdba78511b917e166f0b6dbecSteve Pfetsch *  Description:   Contains controller-specific functions, like
27635682da6daf370cdba78511b917e166f0b6dbecSteve Pfetsch *                      firmware patch download
28635682da6daf370cdba78511b917e166f0b6dbecSteve Pfetsch *                      low power mode operations
29635682da6daf370cdba78511b917e166f0b6dbecSteve Pfetsch *
30635682da6daf370cdba78511b917e166f0b6dbecSteve Pfetsch ******************************************************************************/
31635682da6daf370cdba78511b917e166f0b6dbecSteve Pfetsch#ifdef __cplusplus
32635682da6daf370cdba78511b917e166f0b6dbecSteve Pfetschextern "C" {
33635682da6daf370cdba78511b917e166f0b6dbecSteve Pfetsch#endif
34635682da6daf370cdba78511b917e166f0b6dbecSteve Pfetsch
35635682da6daf370cdba78511b917e166f0b6dbecSteve Pfetsch#define LOG_TAG "bt_vendor"
36635682da6daf370cdba78511b917e166f0b6dbecSteve Pfetsch
37dce6a114229a6ecf183a45ef9f95e3147afdb07aSteven Moreland#include <sys/uio.h>
38635682da6daf370cdba78511b917e166f0b6dbecSteve Pfetsch#include <sys/socket.h>
39dce6a114229a6ecf183a45ef9f95e3147afdb07aSteven Moreland#include <log/log.h>
40635682da6daf370cdba78511b917e166f0b6dbecSteve Pfetsch#include <sys/types.h>
41635682da6daf370cdba78511b917e166f0b6dbecSteve Pfetsch#include <sys/stat.h>
42635682da6daf370cdba78511b917e166f0b6dbecSteve Pfetsch#include <signal.h>
43635682da6daf370cdba78511b917e166f0b6dbecSteve Pfetsch#include <time.h>
44635682da6daf370cdba78511b917e166f0b6dbecSteve Pfetsch#include <errno.h>
45635682da6daf370cdba78511b917e166f0b6dbecSteve Pfetsch#include <fcntl.h>
46635682da6daf370cdba78511b917e166f0b6dbecSteve Pfetsch#include <dirent.h>
47635682da6daf370cdba78511b917e166f0b6dbecSteve Pfetsch#include <ctype.h>
48635682da6daf370cdba78511b917e166f0b6dbecSteve Pfetsch#include <cutils/properties.h>
49635682da6daf370cdba78511b917e166f0b6dbecSteve Pfetsch#include <stdlib.h>
50635682da6daf370cdba78511b917e166f0b6dbecSteve Pfetsch#include <string.h>
51635682da6daf370cdba78511b917e166f0b6dbecSteve Pfetsch#include <termios.h>
52635682da6daf370cdba78511b917e166f0b6dbecSteve Pfetsch#include <string.h>
53dce6a114229a6ecf183a45ef9f95e3147afdb07aSteven Moreland#include <unistd.h>
54635682da6daf370cdba78511b917e166f0b6dbecSteve Pfetsch
55635682da6daf370cdba78511b917e166f0b6dbecSteve Pfetsch#include "bt_hci_bdroid.h"
56635682da6daf370cdba78511b917e166f0b6dbecSteve Pfetsch#include "hci_uart.h"
57635682da6daf370cdba78511b917e166f0b6dbecSteve Pfetsch#include "hw_ar3k.h"
58635682da6daf370cdba78511b917e166f0b6dbecSteve Pfetsch
59635682da6daf370cdba78511b917e166f0b6dbecSteve Pfetsch/******************************************************************************
60635682da6daf370cdba78511b917e166f0b6dbecSteve Pfetsch**  Variables
61635682da6daf370cdba78511b917e166f0b6dbecSteve Pfetsch******************************************************************************/
62635682da6daf370cdba78511b917e166f0b6dbecSteve Pfetschint cbstat = 0;
63635682da6daf370cdba78511b917e166f0b6dbecSteve Pfetsch#define PATCH_LOC_STRING_LEN   8
64635682da6daf370cdba78511b917e166f0b6dbecSteve Pfetschchar ARbyte[3];
65635682da6daf370cdba78511b917e166f0b6dbecSteve Pfetschchar ARptr[MAX_PATCH_CMD + 1];
66635682da6daf370cdba78511b917e166f0b6dbecSteve Pfetschint byte_cnt;
67635682da6daf370cdba78511b917e166f0b6dbecSteve Pfetschint patch_count = 0;
68635682da6daf370cdba78511b917e166f0b6dbecSteve Pfetschchar patch_loc[PATCH_LOC_STRING_LEN + 1];
69635682da6daf370cdba78511b917e166f0b6dbecSteve Pfetschint PSCounter=0;
70635682da6daf370cdba78511b917e166f0b6dbecSteve Pfetsch
71635682da6daf370cdba78511b917e166f0b6dbecSteve Pfetschuint32_t dev_type = 0;
72635682da6daf370cdba78511b917e166f0b6dbecSteve Pfetschuint32_t rom_version = 0;
73635682da6daf370cdba78511b917e166f0b6dbecSteve Pfetschuint32_t build_version = 0;
74635682da6daf370cdba78511b917e166f0b6dbecSteve Pfetsch
75635682da6daf370cdba78511b917e166f0b6dbecSteve Pfetschchar patch_file[PATH_MAX];
76635682da6daf370cdba78511b917e166f0b6dbecSteve Pfetschchar ps_file[PATH_MAX];
77635682da6daf370cdba78511b917e166f0b6dbecSteve PfetschFILE *stream;
78635682da6daf370cdba78511b917e166f0b6dbecSteve Pfetschint tag_count=0;
79635682da6daf370cdba78511b917e166f0b6dbecSteve Pfetsch
80635682da6daf370cdba78511b917e166f0b6dbecSteve Pfetsch/* for friendly debugging outpout string */
81635682da6daf370cdba78511b917e166f0b6dbecSteve Pfetschstatic char *lpm_mode[] = {
82635682da6daf370cdba78511b917e166f0b6dbecSteve Pfetsch    "UNKNOWN",
83635682da6daf370cdba78511b917e166f0b6dbecSteve Pfetsch    "disabled",
84635682da6daf370cdba78511b917e166f0b6dbecSteve Pfetsch    "enabled"
85635682da6daf370cdba78511b917e166f0b6dbecSteve Pfetsch};
86635682da6daf370cdba78511b917e166f0b6dbecSteve Pfetsch
87635682da6daf370cdba78511b917e166f0b6dbecSteve Pfetschstatic char *lpm_state[] = {
88635682da6daf370cdba78511b917e166f0b6dbecSteve Pfetsch    "UNKNOWN",
89635682da6daf370cdba78511b917e166f0b6dbecSteve Pfetsch    "de-asserted",
90635682da6daf370cdba78511b917e166f0b6dbecSteve Pfetsch    "asserted"
91635682da6daf370cdba78511b917e166f0b6dbecSteve Pfetsch};
92635682da6daf370cdba78511b917e166f0b6dbecSteve Pfetsch
93635682da6daf370cdba78511b917e166f0b6dbecSteve Pfetschstatic uint8_t upio_state[UPIO_MAX_COUNT];
94635682da6daf370cdba78511b917e166f0b6dbecSteve Pfetschstruct ps_cfg_entry ps_list[MAX_TAGS];
95635682da6daf370cdba78511b917e166f0b6dbecSteve Pfetsch
96635682da6daf370cdba78511b917e166f0b6dbecSteve Pfetsch#define PS_EVENT_LEN 100
97635682da6daf370cdba78511b917e166f0b6dbecSteve Pfetsch
98635682da6daf370cdba78511b917e166f0b6dbecSteve Pfetsch#ifdef __cplusplus
99635682da6daf370cdba78511b917e166f0b6dbecSteve Pfetsch}
100635682da6daf370cdba78511b917e166f0b6dbecSteve Pfetsch#endif
101635682da6daf370cdba78511b917e166f0b6dbecSteve Pfetsch
102635682da6daf370cdba78511b917e166f0b6dbecSteve Pfetsch#define RESERVED(p)  if(p) ALOGI( "%s: reserved param", __FUNCTION__);
103635682da6daf370cdba78511b917e166f0b6dbecSteve Pfetsch
104635682da6daf370cdba78511b917e166f0b6dbecSteve Pfetsch/*****************************************************************************
105635682da6daf370cdba78511b917e166f0b6dbecSteve Pfetsch**   Functions
106635682da6daf370cdba78511b917e166f0b6dbecSteve Pfetsch*****************************************************************************/
107635682da6daf370cdba78511b917e166f0b6dbecSteve Pfetsch
108635682da6daf370cdba78511b917e166f0b6dbecSteve Pfetschint is_bt_soc_ath() {
109635682da6daf370cdba78511b917e166f0b6dbecSteve Pfetsch    int ret = 0;
110635682da6daf370cdba78511b917e166f0b6dbecSteve Pfetsch    char bt_soc_type[PROPERTY_VALUE_MAX];
111635682da6daf370cdba78511b917e166f0b6dbecSteve Pfetsch    ret = property_get("qcom.bluetooth.soc", bt_soc_type, NULL);
112635682da6daf370cdba78511b917e166f0b6dbecSteve Pfetsch    if (ret != 0) {
113635682da6daf370cdba78511b917e166f0b6dbecSteve Pfetsch        ALOGI("qcom.bluetooth.soc set to %s\n", bt_soc_type);
114635682da6daf370cdba78511b917e166f0b6dbecSteve Pfetsch        if (!strncasecmp(bt_soc_type, "ath3k", sizeof("ath3k")))
115635682da6daf370cdba78511b917e166f0b6dbecSteve Pfetsch            return 1;
116635682da6daf370cdba78511b917e166f0b6dbecSteve Pfetsch    } else {
117635682da6daf370cdba78511b917e166f0b6dbecSteve Pfetsch        ALOGI("qcom.bluetooth.soc not set, so using default.\n");
118635682da6daf370cdba78511b917e166f0b6dbecSteve Pfetsch    }
119635682da6daf370cdba78511b917e166f0b6dbecSteve Pfetsch
120635682da6daf370cdba78511b917e166f0b6dbecSteve Pfetsch    return 0;
121635682da6daf370cdba78511b917e166f0b6dbecSteve Pfetsch}
122635682da6daf370cdba78511b917e166f0b6dbecSteve Pfetsch
123635682da6daf370cdba78511b917e166f0b6dbecSteve Pfetsch/*
124635682da6daf370cdba78511b917e166f0b6dbecSteve Pfetsch * Send HCI command and wait for command complete event.
125635682da6daf370cdba78511b917e166f0b6dbecSteve Pfetsch * The event buffer has to be freed by the caller.
126635682da6daf370cdba78511b917e166f0b6dbecSteve Pfetsch */
127635682da6daf370cdba78511b917e166f0b6dbecSteve Pfetsch
128635682da6daf370cdba78511b917e166f0b6dbecSteve Pfetschstatic int send_hci_cmd_sync(int dev, uint8_t *cmd, int len, uint8_t **event)
129635682da6daf370cdba78511b917e166f0b6dbecSteve Pfetsch{
130635682da6daf370cdba78511b917e166f0b6dbecSteve Pfetsch    int err;
131635682da6daf370cdba78511b917e166f0b6dbecSteve Pfetsch    uint8_t *hci_event;
132635682da6daf370cdba78511b917e166f0b6dbecSteve Pfetsch    uint8_t pkt_type = HCI_COMMAND_PKT;
133635682da6daf370cdba78511b917e166f0b6dbecSteve Pfetsch
134635682da6daf370cdba78511b917e166f0b6dbecSteve Pfetsch    if (len == 0)
135635682da6daf370cdba78511b917e166f0b6dbecSteve Pfetsch    return len;
136635682da6daf370cdba78511b917e166f0b6dbecSteve Pfetsch
137635682da6daf370cdba78511b917e166f0b6dbecSteve Pfetsch    if (write(dev, &pkt_type, 1) != 1)
138635682da6daf370cdba78511b917e166f0b6dbecSteve Pfetsch        return -EILSEQ;
139635682da6daf370cdba78511b917e166f0b6dbecSteve Pfetsch    if (write(dev, (unsigned char *)cmd, len) != len)
140635682da6daf370cdba78511b917e166f0b6dbecSteve Pfetsch        return -EILSEQ;
141635682da6daf370cdba78511b917e166f0b6dbecSteve Pfetsch
142635682da6daf370cdba78511b917e166f0b6dbecSteve Pfetsch    hci_event = (uint8_t *)malloc(PS_EVENT_LEN);
143635682da6daf370cdba78511b917e166f0b6dbecSteve Pfetsch    if (!hci_event)
144635682da6daf370cdba78511b917e166f0b6dbecSteve Pfetsch        return -ENOMEM;
145635682da6daf370cdba78511b917e166f0b6dbecSteve Pfetsch
146635682da6daf370cdba78511b917e166f0b6dbecSteve Pfetsch    err = read_hci_event(dev, (unsigned char *)hci_event, PS_EVENT_LEN);
147635682da6daf370cdba78511b917e166f0b6dbecSteve Pfetsch    if (err > 0) {
148635682da6daf370cdba78511b917e166f0b6dbecSteve Pfetsch        *event = hci_event;
149635682da6daf370cdba78511b917e166f0b6dbecSteve Pfetsch    } else {
150635682da6daf370cdba78511b917e166f0b6dbecSteve Pfetsch        free(hci_event);
151635682da6daf370cdba78511b917e166f0b6dbecSteve Pfetsch        return -EILSEQ;
152635682da6daf370cdba78511b917e166f0b6dbecSteve Pfetsch    }
153635682da6daf370cdba78511b917e166f0b6dbecSteve Pfetsch
154635682da6daf370cdba78511b917e166f0b6dbecSteve Pfetsch    return len;
155635682da6daf370cdba78511b917e166f0b6dbecSteve Pfetsch}
156635682da6daf370cdba78511b917e166f0b6dbecSteve Pfetsch
157635682da6daf370cdba78511b917e166f0b6dbecSteve Pfetschstatic void convert_bdaddr(char *str_bdaddr, char *bdaddr)
158635682da6daf370cdba78511b917e166f0b6dbecSteve Pfetsch{
159635682da6daf370cdba78511b917e166f0b6dbecSteve Pfetsch    char bdbyte[3];
160635682da6daf370cdba78511b917e166f0b6dbecSteve Pfetsch    char *str_byte = str_bdaddr;
161635682da6daf370cdba78511b917e166f0b6dbecSteve Pfetsch    int i, j;
162635682da6daf370cdba78511b917e166f0b6dbecSteve Pfetsch    int colon_present = 0;
163635682da6daf370cdba78511b917e166f0b6dbecSteve Pfetsch
164635682da6daf370cdba78511b917e166f0b6dbecSteve Pfetsch    if (strstr(str_bdaddr, ":"))
165635682da6daf370cdba78511b917e166f0b6dbecSteve Pfetsch        colon_present = 1;
166635682da6daf370cdba78511b917e166f0b6dbecSteve Pfetsch
167635682da6daf370cdba78511b917e166f0b6dbecSteve Pfetsch    bdbyte[2] = '\0';
168635682da6daf370cdba78511b917e166f0b6dbecSteve Pfetsch
169635682da6daf370cdba78511b917e166f0b6dbecSteve Pfetsch    /* Reverse the BDADDR to LSB first */
170635682da6daf370cdba78511b917e166f0b6dbecSteve Pfetsch    for (i = 0, j = 5; i < 6; i++, j--) {
171635682da6daf370cdba78511b917e166f0b6dbecSteve Pfetsch        bdbyte[0] = str_byte[0];
172635682da6daf370cdba78511b917e166f0b6dbecSteve Pfetsch        bdbyte[1] = str_byte[1];
173635682da6daf370cdba78511b917e166f0b6dbecSteve Pfetsch        bdaddr[j] = strtol(bdbyte, NULL, 16);
174635682da6daf370cdba78511b917e166f0b6dbecSteve Pfetsch
175635682da6daf370cdba78511b917e166f0b6dbecSteve Pfetsch        if (colon_present == 1)
176635682da6daf370cdba78511b917e166f0b6dbecSteve Pfetsch            str_byte += 3;
177635682da6daf370cdba78511b917e166f0b6dbecSteve Pfetsch        else
178635682da6daf370cdba78511b917e166f0b6dbecSteve Pfetsch            str_byte += 2;
179635682da6daf370cdba78511b917e166f0b6dbecSteve Pfetsch    }
180635682da6daf370cdba78511b917e166f0b6dbecSteve Pfetsch}
181635682da6daf370cdba78511b917e166f0b6dbecSteve Pfetsch
182635682da6daf370cdba78511b917e166f0b6dbecSteve Pfetschstatic int uart_speed(int s)
183635682da6daf370cdba78511b917e166f0b6dbecSteve Pfetsch{
184635682da6daf370cdba78511b917e166f0b6dbecSteve Pfetsch    switch (s) {
185635682da6daf370cdba78511b917e166f0b6dbecSteve Pfetsch        case 9600:
186635682da6daf370cdba78511b917e166f0b6dbecSteve Pfetsch            return B9600;
187635682da6daf370cdba78511b917e166f0b6dbecSteve Pfetsch        case 19200:
188635682da6daf370cdba78511b917e166f0b6dbecSteve Pfetsch            return B19200;
189635682da6daf370cdba78511b917e166f0b6dbecSteve Pfetsch        case 38400:
190635682da6daf370cdba78511b917e166f0b6dbecSteve Pfetsch            return B38400;
191635682da6daf370cdba78511b917e166f0b6dbecSteve Pfetsch        case 57600:
192635682da6daf370cdba78511b917e166f0b6dbecSteve Pfetsch            return B57600;
193635682da6daf370cdba78511b917e166f0b6dbecSteve Pfetsch        case 115200:
194635682da6daf370cdba78511b917e166f0b6dbecSteve Pfetsch            return B115200;
195635682da6daf370cdba78511b917e166f0b6dbecSteve Pfetsch        case 230400:
196635682da6daf370cdba78511b917e166f0b6dbecSteve Pfetsch            return B230400;
197635682da6daf370cdba78511b917e166f0b6dbecSteve Pfetsch        case 460800:
198635682da6daf370cdba78511b917e166f0b6dbecSteve Pfetsch            return B460800;
199635682da6daf370cdba78511b917e166f0b6dbecSteve Pfetsch        case 500000:
200635682da6daf370cdba78511b917e166f0b6dbecSteve Pfetsch            return B500000;
201635682da6daf370cdba78511b917e166f0b6dbecSteve Pfetsch        case 576000:
202635682da6daf370cdba78511b917e166f0b6dbecSteve Pfetsch            return B576000;
203635682da6daf370cdba78511b917e166f0b6dbecSteve Pfetsch        case 921600:
204635682da6daf370cdba78511b917e166f0b6dbecSteve Pfetsch            return B921600;
205635682da6daf370cdba78511b917e166f0b6dbecSteve Pfetsch        case 1000000:
206635682da6daf370cdba78511b917e166f0b6dbecSteve Pfetsch            return B1000000;
207635682da6daf370cdba78511b917e166f0b6dbecSteve Pfetsch        case 1152000:
208635682da6daf370cdba78511b917e166f0b6dbecSteve Pfetsch            return B1152000;
209635682da6daf370cdba78511b917e166f0b6dbecSteve Pfetsch        case 1500000:
210635682da6daf370cdba78511b917e166f0b6dbecSteve Pfetsch            return B1500000;
211635682da6daf370cdba78511b917e166f0b6dbecSteve Pfetsch        case 2000000:
212635682da6daf370cdba78511b917e166f0b6dbecSteve Pfetsch            return B2000000;
213635682da6daf370cdba78511b917e166f0b6dbecSteve Pfetsch#ifdef B2500000
214635682da6daf370cdba78511b917e166f0b6dbecSteve Pfetsch        case 2500000:
215635682da6daf370cdba78511b917e166f0b6dbecSteve Pfetsch            return B2500000;
216635682da6daf370cdba78511b917e166f0b6dbecSteve Pfetsch#endif
217635682da6daf370cdba78511b917e166f0b6dbecSteve Pfetsch#ifdef B3000000
218635682da6daf370cdba78511b917e166f0b6dbecSteve Pfetsch        case 3000000:
219635682da6daf370cdba78511b917e166f0b6dbecSteve Pfetsch            return B3000000;
220635682da6daf370cdba78511b917e166f0b6dbecSteve Pfetsch#endif
221635682da6daf370cdba78511b917e166f0b6dbecSteve Pfetsch#ifdef B3500000
222635682da6daf370cdba78511b917e166f0b6dbecSteve Pfetsch        case 3500000:
223635682da6daf370cdba78511b917e166f0b6dbecSteve Pfetsch            return B3500000;
224635682da6daf370cdba78511b917e166f0b6dbecSteve Pfetsch#endif
225635682da6daf370cdba78511b917e166f0b6dbecSteve Pfetsch#ifdef B4000000
226635682da6daf370cdba78511b917e166f0b6dbecSteve Pfetsch        case 4000000:
227635682da6daf370cdba78511b917e166f0b6dbecSteve Pfetsch            return B4000000;
228635682da6daf370cdba78511b917e166f0b6dbecSteve Pfetsch#endif
229635682da6daf370cdba78511b917e166f0b6dbecSteve Pfetsch        default:
230635682da6daf370cdba78511b917e166f0b6dbecSteve Pfetsch            return B57600;
231635682da6daf370cdba78511b917e166f0b6dbecSteve Pfetsch    }
232635682da6daf370cdba78511b917e166f0b6dbecSteve Pfetsch}
233635682da6daf370cdba78511b917e166f0b6dbecSteve Pfetsch
234635682da6daf370cdba78511b917e166f0b6dbecSteve Pfetschint set_speed(int fd, struct termios *ti, int speed)
235635682da6daf370cdba78511b917e166f0b6dbecSteve Pfetsch{
236635682da6daf370cdba78511b917e166f0b6dbecSteve Pfetsch    if (cfsetospeed(ti, uart_speed(speed)) < 0)
237635682da6daf370cdba78511b917e166f0b6dbecSteve Pfetsch        return -errno;
238635682da6daf370cdba78511b917e166f0b6dbecSteve Pfetsch
239635682da6daf370cdba78511b917e166f0b6dbecSteve Pfetsch    if (cfsetispeed(ti, uart_speed(speed)) < 0)
240635682da6daf370cdba78511b917e166f0b6dbecSteve Pfetsch        return -errno;
241635682da6daf370cdba78511b917e166f0b6dbecSteve Pfetsch
242635682da6daf370cdba78511b917e166f0b6dbecSteve Pfetsch    if (tcsetattr(fd, TCSANOW, ti) < 0)
243635682da6daf370cdba78511b917e166f0b6dbecSteve Pfetsch        return -errno;
244635682da6daf370cdba78511b917e166f0b6dbecSteve Pfetsch
245635682da6daf370cdba78511b917e166f0b6dbecSteve Pfetsch    return 0;
246635682da6daf370cdba78511b917e166f0b6dbecSteve Pfetsch}
247635682da6daf370cdba78511b917e166f0b6dbecSteve Pfetsch
248635682da6daf370cdba78511b917e166f0b6dbecSteve Pfetschstatic void load_hci_ps_hdr(uint8_t *cmd, uint8_t ps_op, int len, int index)
249635682da6daf370cdba78511b917e166f0b6dbecSteve Pfetsch{
250635682da6daf370cdba78511b917e166f0b6dbecSteve Pfetsch    hci_command_hdr *ch = (void *)cmd;
251635682da6daf370cdba78511b917e166f0b6dbecSteve Pfetsch
252635682da6daf370cdba78511b917e166f0b6dbecSteve Pfetsch    ch->opcode = htobs(cmd_opcode_pack(HCI_VENDOR_CMD_OGF,
253635682da6daf370cdba78511b917e166f0b6dbecSteve Pfetsch        HCI_PS_CMD_OCF));
254635682da6daf370cdba78511b917e166f0b6dbecSteve Pfetsch    ch->plen = len + PS_HDR_LEN;
255635682da6daf370cdba78511b917e166f0b6dbecSteve Pfetsch    cmd += HCI_COMMAND_HDR_SIZE;
256635682da6daf370cdba78511b917e166f0b6dbecSteve Pfetsch
257635682da6daf370cdba78511b917e166f0b6dbecSteve Pfetsch    cmd[0] = ps_op;
258635682da6daf370cdba78511b917e166f0b6dbecSteve Pfetsch    cmd[1] = index;
259635682da6daf370cdba78511b917e166f0b6dbecSteve Pfetsch    cmd[2] = index >> 8;
260635682da6daf370cdba78511b917e166f0b6dbecSteve Pfetsch    cmd[3] = len;
261635682da6daf370cdba78511b917e166f0b6dbecSteve Pfetsch}
262635682da6daf370cdba78511b917e166f0b6dbecSteve Pfetsch
263635682da6daf370cdba78511b917e166f0b6dbecSteve Pfetsch
264635682da6daf370cdba78511b917e166f0b6dbecSteve Pfetschstatic int read_ps_event(uint8_t *event, uint16_t ocf)
265635682da6daf370cdba78511b917e166f0b6dbecSteve Pfetsch{
266635682da6daf370cdba78511b917e166f0b6dbecSteve Pfetsch    hci_event_hdr *eh;
267635682da6daf370cdba78511b917e166f0b6dbecSteve Pfetsch    uint16_t opcode = htobs(cmd_opcode_pack(HCI_VENDOR_CMD_OGF, ocf));
268635682da6daf370cdba78511b917e166f0b6dbecSteve Pfetsch
269635682da6daf370cdba78511b917e166f0b6dbecSteve Pfetsch    event++;
270635682da6daf370cdba78511b917e166f0b6dbecSteve Pfetsch
271635682da6daf370cdba78511b917e166f0b6dbecSteve Pfetsch    eh = (void *)event;
272635682da6daf370cdba78511b917e166f0b6dbecSteve Pfetsch    event += HCI_EVENT_HDR_SIZE;
273635682da6daf370cdba78511b917e166f0b6dbecSteve Pfetsch
274635682da6daf370cdba78511b917e166f0b6dbecSteve Pfetsch    if (eh->evt == EVT_CMD_COMPLETE) {
275635682da6daf370cdba78511b917e166f0b6dbecSteve Pfetsch        evt_cmd_complete *cc = (void *)event;
276635682da6daf370cdba78511b917e166f0b6dbecSteve Pfetsch
277635682da6daf370cdba78511b917e166f0b6dbecSteve Pfetsch        event += EVT_CMD_COMPLETE_SIZE;
278635682da6daf370cdba78511b917e166f0b6dbecSteve Pfetsch
279635682da6daf370cdba78511b917e166f0b6dbecSteve Pfetsch        if (cc->opcode == opcode && event[0] == HCI_EV_SUCCESS)
280635682da6daf370cdba78511b917e166f0b6dbecSteve Pfetsch            return 0;
281635682da6daf370cdba78511b917e166f0b6dbecSteve Pfetsch        else
282635682da6daf370cdba78511b917e166f0b6dbecSteve Pfetsch            return -EILSEQ;
283635682da6daf370cdba78511b917e166f0b6dbecSteve Pfetsch    }
284635682da6daf370cdba78511b917e166f0b6dbecSteve Pfetsch
285635682da6daf370cdba78511b917e166f0b6dbecSteve Pfetsch    return -EILSEQ;
286635682da6daf370cdba78511b917e166f0b6dbecSteve Pfetsch}
287635682da6daf370cdba78511b917e166f0b6dbecSteve Pfetsch
288635682da6daf370cdba78511b917e166f0b6dbecSteve Pfetsch#define PS_WRITE           1
289635682da6daf370cdba78511b917e166f0b6dbecSteve Pfetsch#define PS_RESET           2
290635682da6daf370cdba78511b917e166f0b6dbecSteve Pfetsch#define WRITE_PATCH        8
291635682da6daf370cdba78511b917e166f0b6dbecSteve Pfetsch#define ENABLE_PATCH       11
292635682da6daf370cdba78511b917e166f0b6dbecSteve Pfetsch
293635682da6daf370cdba78511b917e166f0b6dbecSteve Pfetsch#define HCI_PS_CMD_HDR_LEN 7
294635682da6daf370cdba78511b917e166f0b6dbecSteve Pfetsch
295635682da6daf370cdba78511b917e166f0b6dbecSteve Pfetschstatic int write_cmd(int fd, uint8_t *buffer, int len)
296635682da6daf370cdba78511b917e166f0b6dbecSteve Pfetsch{
297635682da6daf370cdba78511b917e166f0b6dbecSteve Pfetsch    uint8_t *event;
298635682da6daf370cdba78511b917e166f0b6dbecSteve Pfetsch    int err;
299635682da6daf370cdba78511b917e166f0b6dbecSteve Pfetsch
300635682da6daf370cdba78511b917e166f0b6dbecSteve Pfetsch    err = send_hci_cmd_sync(fd, buffer, len, &event);
301635682da6daf370cdba78511b917e166f0b6dbecSteve Pfetsch    if (err < 0)
302635682da6daf370cdba78511b917e166f0b6dbecSteve Pfetsch        return err;
303635682da6daf370cdba78511b917e166f0b6dbecSteve Pfetsch
304635682da6daf370cdba78511b917e166f0b6dbecSteve Pfetsch    err = read_ps_event(event, HCI_PS_CMD_OCF);
305635682da6daf370cdba78511b917e166f0b6dbecSteve Pfetsch
306635682da6daf370cdba78511b917e166f0b6dbecSteve Pfetsch    free(event);
307635682da6daf370cdba78511b917e166f0b6dbecSteve Pfetsch
308635682da6daf370cdba78511b917e166f0b6dbecSteve Pfetsch    return err;
309635682da6daf370cdba78511b917e166f0b6dbecSteve Pfetsch}
310635682da6daf370cdba78511b917e166f0b6dbecSteve Pfetsch
311635682da6daf370cdba78511b917e166f0b6dbecSteve Pfetsch#define PS_RESET_PARAM_LEN 6
312635682da6daf370cdba78511b917e166f0b6dbecSteve Pfetsch#define PS_RESET_CMD_LEN   (HCI_PS_CMD_HDR_LEN + PS_RESET_PARAM_LEN)
313635682da6daf370cdba78511b917e166f0b6dbecSteve Pfetsch
314635682da6daf370cdba78511b917e166f0b6dbecSteve Pfetsch#define PS_ID_MASK         0xFF
315635682da6daf370cdba78511b917e166f0b6dbecSteve Pfetsch
316635682da6daf370cdba78511b917e166f0b6dbecSteve Pfetsch/* Sends PS commands using vendor specficic HCI commands */
317635682da6daf370cdba78511b917e166f0b6dbecSteve Pfetschstatic int write_ps_cmd(int fd, uint8_t opcode, uint32_t ps_param)
318635682da6daf370cdba78511b917e166f0b6dbecSteve Pfetsch{
319635682da6daf370cdba78511b917e166f0b6dbecSteve Pfetsch    uint8_t cmd[HCI_MAX_CMD_SIZE];
320635682da6daf370cdba78511b917e166f0b6dbecSteve Pfetsch    uint32_t i;
321635682da6daf370cdba78511b917e166f0b6dbecSteve Pfetsch
322635682da6daf370cdba78511b917e166f0b6dbecSteve Pfetsch    switch (opcode) {
323635682da6daf370cdba78511b917e166f0b6dbecSteve Pfetsch        case ENABLE_PATCH:
324635682da6daf370cdba78511b917e166f0b6dbecSteve Pfetsch            load_hci_ps_hdr(cmd, opcode, 0, 0x00);
325635682da6daf370cdba78511b917e166f0b6dbecSteve Pfetsch
326635682da6daf370cdba78511b917e166f0b6dbecSteve Pfetsch            if (write_cmd(fd, cmd, HCI_PS_CMD_HDR_LEN) < 0)
327635682da6daf370cdba78511b917e166f0b6dbecSteve Pfetsch                return -EILSEQ;
328635682da6daf370cdba78511b917e166f0b6dbecSteve Pfetsch            break;
329635682da6daf370cdba78511b917e166f0b6dbecSteve Pfetsch
330635682da6daf370cdba78511b917e166f0b6dbecSteve Pfetsch        case PS_RESET:
331635682da6daf370cdba78511b917e166f0b6dbecSteve Pfetsch            load_hci_ps_hdr(cmd, opcode, PS_RESET_PARAM_LEN, 0x00);
332635682da6daf370cdba78511b917e166f0b6dbecSteve Pfetsch
333635682da6daf370cdba78511b917e166f0b6dbecSteve Pfetsch            cmd[7] = 0x00;
334635682da6daf370cdba78511b917e166f0b6dbecSteve Pfetsch            cmd[PS_RESET_CMD_LEN - 2] = ps_param & PS_ID_MASK;
335635682da6daf370cdba78511b917e166f0b6dbecSteve Pfetsch            cmd[PS_RESET_CMD_LEN - 1] = (ps_param >> 8) & PS_ID_MASK;
336635682da6daf370cdba78511b917e166f0b6dbecSteve Pfetsch
337635682da6daf370cdba78511b917e166f0b6dbecSteve Pfetsch            if (write_cmd(fd, cmd, PS_RESET_CMD_LEN) < 0)
338635682da6daf370cdba78511b917e166f0b6dbecSteve Pfetsch                return -EILSEQ;
339635682da6daf370cdba78511b917e166f0b6dbecSteve Pfetsch            break;
340635682da6daf370cdba78511b917e166f0b6dbecSteve Pfetsch
341635682da6daf370cdba78511b917e166f0b6dbecSteve Pfetsch        case PS_WRITE:
342635682da6daf370cdba78511b917e166f0b6dbecSteve Pfetsch            for (i = 0; i < ps_param; i++) {
343635682da6daf370cdba78511b917e166f0b6dbecSteve Pfetsch                load_hci_ps_hdr(cmd, opcode, ps_list[i].len,
344635682da6daf370cdba78511b917e166f0b6dbecSteve Pfetsch                ps_list[i].id);
345635682da6daf370cdba78511b917e166f0b6dbecSteve Pfetsch
346635682da6daf370cdba78511b917e166f0b6dbecSteve Pfetsch                memcpy(&cmd[HCI_PS_CMD_HDR_LEN], ps_list[i].data,
347635682da6daf370cdba78511b917e166f0b6dbecSteve Pfetsch                ps_list[i].len);
348635682da6daf370cdba78511b917e166f0b6dbecSteve Pfetsch
349635682da6daf370cdba78511b917e166f0b6dbecSteve Pfetsch                if (write_cmd(fd, cmd, ps_list[i].len +
350635682da6daf370cdba78511b917e166f0b6dbecSteve Pfetsch                    HCI_PS_CMD_HDR_LEN) < 0)
351635682da6daf370cdba78511b917e166f0b6dbecSteve Pfetsch                    return -EILSEQ;
352635682da6daf370cdba78511b917e166f0b6dbecSteve Pfetsch            }
353635682da6daf370cdba78511b917e166f0b6dbecSteve Pfetsch            break;
354635682da6daf370cdba78511b917e166f0b6dbecSteve Pfetsch    }
355635682da6daf370cdba78511b917e166f0b6dbecSteve Pfetsch
356635682da6daf370cdba78511b917e166f0b6dbecSteve Pfetsch    return 0;
357635682da6daf370cdba78511b917e166f0b6dbecSteve Pfetsch}
358635682da6daf370cdba78511b917e166f0b6dbecSteve Pfetsch
359635682da6daf370cdba78511b917e166f0b6dbecSteve Pfetsch#define PS_ASIC_FILE    "PS_ASIC.pst"
360635682da6daf370cdba78511b917e166f0b6dbecSteve Pfetsch#define PS_FPGA_FILE    "PS_FPGA.pst"
361635682da6daf370cdba78511b917e166f0b6dbecSteve Pfetsch#define MAXPATHLEN  4096
362635682da6daf370cdba78511b917e166f0b6dbecSteve Pfetschstatic void get_ps_file_name(uint32_t devtype, uint32_t rom_version,char *path)
363635682da6daf370cdba78511b917e166f0b6dbecSteve Pfetsch{
364635682da6daf370cdba78511b917e166f0b6dbecSteve Pfetsch    char *filename;
365635682da6daf370cdba78511b917e166f0b6dbecSteve Pfetsch
366635682da6daf370cdba78511b917e166f0b6dbecSteve Pfetsch    if (devtype == 0xdeadc0de)
367635682da6daf370cdba78511b917e166f0b6dbecSteve Pfetsch        filename = PS_ASIC_FILE;
368635682da6daf370cdba78511b917e166f0b6dbecSteve Pfetsch    else
369635682da6daf370cdba78511b917e166f0b6dbecSteve Pfetsch        filename = PS_FPGA_FILE;
370635682da6daf370cdba78511b917e166f0b6dbecSteve Pfetsch
371635682da6daf370cdba78511b917e166f0b6dbecSteve Pfetsch    snprintf(path, MAXPATHLEN, "%s%x/%s", FW_PATH, rom_version, filename);
372635682da6daf370cdba78511b917e166f0b6dbecSteve Pfetsch}
373635682da6daf370cdba78511b917e166f0b6dbecSteve Pfetsch
374635682da6daf370cdba78511b917e166f0b6dbecSteve Pfetsch#define PATCH_FILE        "RamPatch.txt"
375635682da6daf370cdba78511b917e166f0b6dbecSteve Pfetsch#define FPGA_ROM_VERSION  0x99999999
376635682da6daf370cdba78511b917e166f0b6dbecSteve Pfetsch#define ROM_DEV_TYPE      0xdeadc0de
377635682da6daf370cdba78511b917e166f0b6dbecSteve Pfetsch
378635682da6daf370cdba78511b917e166f0b6dbecSteve Pfetschstatic void get_patch_file_name(uint32_t dev_type, uint32_t rom_version,
379635682da6daf370cdba78511b917e166f0b6dbecSteve Pfetsch    uint32_t build_version, char *path)
380635682da6daf370cdba78511b917e166f0b6dbecSteve Pfetsch{
381635682da6daf370cdba78511b917e166f0b6dbecSteve Pfetsch    if (rom_version == FPGA_ROM_VERSION && dev_type != ROM_DEV_TYPE
382635682da6daf370cdba78511b917e166f0b6dbecSteve Pfetsch            &&dev_type != 0 && build_version == 1)
383635682da6daf370cdba78511b917e166f0b6dbecSteve Pfetsch        path[0] = '\0';
384635682da6daf370cdba78511b917e166f0b6dbecSteve Pfetsch    else
385635682da6daf370cdba78511b917e166f0b6dbecSteve Pfetsch        snprintf(path, MAXPATHLEN, "%s%x/%s", FW_PATH, rom_version, PATCH_FILE);
386635682da6daf370cdba78511b917e166f0b6dbecSteve Pfetsch}
387635682da6daf370cdba78511b917e166f0b6dbecSteve Pfetsch
388635682da6daf370cdba78511b917e166f0b6dbecSteve Pfetschstatic int set_cntrlr_baud(int fd, int speed)
389635682da6daf370cdba78511b917e166f0b6dbecSteve Pfetsch{
390635682da6daf370cdba78511b917e166f0b6dbecSteve Pfetsch    int baud;
391635682da6daf370cdba78511b917e166f0b6dbecSteve Pfetsch    struct timespec tm = { 0, 500000};
392635682da6daf370cdba78511b917e166f0b6dbecSteve Pfetsch    unsigned char cmd[MAX_CMD_LEN], rsp[HCI_MAX_EVENT_SIZE];
393635682da6daf370cdba78511b917e166f0b6dbecSteve Pfetsch    unsigned char *ptr = cmd + 1;
394635682da6daf370cdba78511b917e166f0b6dbecSteve Pfetsch    hci_command_hdr *ch = (void *)ptr;
395635682da6daf370cdba78511b917e166f0b6dbecSteve Pfetsch
396635682da6daf370cdba78511b917e166f0b6dbecSteve Pfetsch    cmd[0] = HCI_COMMAND_PKT;
397635682da6daf370cdba78511b917e166f0b6dbecSteve Pfetsch
398635682da6daf370cdba78511b917e166f0b6dbecSteve Pfetsch    /* set controller baud rate to user specified value */
399635682da6daf370cdba78511b917e166f0b6dbecSteve Pfetsch    ptr = cmd + 1;
400635682da6daf370cdba78511b917e166f0b6dbecSteve Pfetsch    ch->opcode = htobs(cmd_opcode_pack(HCI_VENDOR_CMD_OGF,
401635682da6daf370cdba78511b917e166f0b6dbecSteve Pfetsch    HCI_CHG_BAUD_CMD_OCF));
402635682da6daf370cdba78511b917e166f0b6dbecSteve Pfetsch    ch->plen = 2;
403635682da6daf370cdba78511b917e166f0b6dbecSteve Pfetsch    ptr += HCI_COMMAND_HDR_SIZE;
404635682da6daf370cdba78511b917e166f0b6dbecSteve Pfetsch
405635682da6daf370cdba78511b917e166f0b6dbecSteve Pfetsch    baud = speed/100;
406635682da6daf370cdba78511b917e166f0b6dbecSteve Pfetsch    ptr[0] = (char)baud;
407635682da6daf370cdba78511b917e166f0b6dbecSteve Pfetsch    ptr[1] = (char)(baud >> 8);
408635682da6daf370cdba78511b917e166f0b6dbecSteve Pfetsch
409635682da6daf370cdba78511b917e166f0b6dbecSteve Pfetsch    if (write(fd, cmd, WRITE_BAUD_CMD_LEN) != WRITE_BAUD_CMD_LEN) {
410635682da6daf370cdba78511b917e166f0b6dbecSteve Pfetsch        ALOGI("Failed to write change baud rate command");
411635682da6daf370cdba78511b917e166f0b6dbecSteve Pfetsch        return -ETIMEDOUT;
412635682da6daf370cdba78511b917e166f0b6dbecSteve Pfetsch    }
413635682da6daf370cdba78511b917e166f0b6dbecSteve Pfetsch
414635682da6daf370cdba78511b917e166f0b6dbecSteve Pfetsch    nanosleep(&tm, NULL);
415635682da6daf370cdba78511b917e166f0b6dbecSteve Pfetsch
416635682da6daf370cdba78511b917e166f0b6dbecSteve Pfetsch    if (read_hci_event(fd, rsp, sizeof(rsp)) < 0)
417635682da6daf370cdba78511b917e166f0b6dbecSteve Pfetsch        return -ETIMEDOUT;
418635682da6daf370cdba78511b917e166f0b6dbecSteve Pfetsch
419635682da6daf370cdba78511b917e166f0b6dbecSteve Pfetsch    return 0;
420635682da6daf370cdba78511b917e166f0b6dbecSteve Pfetsch}
421635682da6daf370cdba78511b917e166f0b6dbecSteve Pfetsch
422635682da6daf370cdba78511b917e166f0b6dbecSteve Pfetsch#define PS_UNDEF   0
423635682da6daf370cdba78511b917e166f0b6dbecSteve Pfetsch#define PS_ID      1
424635682da6daf370cdba78511b917e166f0b6dbecSteve Pfetsch#define PS_LEN     2
425635682da6daf370cdba78511b917e166f0b6dbecSteve Pfetsch#define PS_DATA    3
426635682da6daf370cdba78511b917e166f0b6dbecSteve Pfetsch
427635682da6daf370cdba78511b917e166f0b6dbecSteve Pfetsch#define PS_MAX_LEN         500
428635682da6daf370cdba78511b917e166f0b6dbecSteve Pfetsch#define LINE_SIZE_MAX      (PS_MAX_LEN * 2)
429635682da6daf370cdba78511b917e166f0b6dbecSteve Pfetsch#define ENTRY_PER_LINE     16
430635682da6daf370cdba78511b917e166f0b6dbecSteve Pfetsch
431635682da6daf370cdba78511b917e166f0b6dbecSteve Pfetsch#define __check_comment(buf) (((buf)[0] == '/') && ((buf)[1] == '/'))
432635682da6daf370cdba78511b917e166f0b6dbecSteve Pfetsch#define __skip_space(str)      while (*(str) == ' ') ((str)++)
433635682da6daf370cdba78511b917e166f0b6dbecSteve Pfetsch
434635682da6daf370cdba78511b917e166f0b6dbecSteve Pfetsch
435635682da6daf370cdba78511b917e166f0b6dbecSteve Pfetsch#define __is_delim(ch) ((ch) == ':')
436635682da6daf370cdba78511b917e166f0b6dbecSteve Pfetsch#define MAX_PREAMBLE_LEN 4
437635682da6daf370cdba78511b917e166f0b6dbecSteve Pfetsch
438635682da6daf370cdba78511b917e166f0b6dbecSteve Pfetsch/* Parse PS entry preamble of format [X:X] for main type and subtype */
439635682da6daf370cdba78511b917e166f0b6dbecSteve Pfetschstatic int get_ps_type(char *ptr, int index, char *type, char *sub_type)
440635682da6daf370cdba78511b917e166f0b6dbecSteve Pfetsch{
441635682da6daf370cdba78511b917e166f0b6dbecSteve Pfetsch    int i;
442e2440ccce4e310cc64ca4f9feb71c61f3e148e8fMarie Janssen    int delim = false;
443635682da6daf370cdba78511b917e166f0b6dbecSteve Pfetsch
444635682da6daf370cdba78511b917e166f0b6dbecSteve Pfetsch    if (index > MAX_PREAMBLE_LEN)
445635682da6daf370cdba78511b917e166f0b6dbecSteve Pfetsch        return -EILSEQ;
446635682da6daf370cdba78511b917e166f0b6dbecSteve Pfetsch
447635682da6daf370cdba78511b917e166f0b6dbecSteve Pfetsch    for (i = 1; i < index; i++) {
448635682da6daf370cdba78511b917e166f0b6dbecSteve Pfetsch        if (__is_delim(ptr[i])) {
449e2440ccce4e310cc64ca4f9feb71c61f3e148e8fMarie Janssen            delim = true;
450635682da6daf370cdba78511b917e166f0b6dbecSteve Pfetsch            continue;
451635682da6daf370cdba78511b917e166f0b6dbecSteve Pfetsch        }
452635682da6daf370cdba78511b917e166f0b6dbecSteve Pfetsch
453635682da6daf370cdba78511b917e166f0b6dbecSteve Pfetsch        if (isalpha(ptr[i])) {
454e2440ccce4e310cc64ca4f9feb71c61f3e148e8fMarie Janssen            if (delim == false)
455635682da6daf370cdba78511b917e166f0b6dbecSteve Pfetsch                (*type) = toupper(ptr[i]);
456635682da6daf370cdba78511b917e166f0b6dbecSteve Pfetsch            else
457635682da6daf370cdba78511b917e166f0b6dbecSteve Pfetsch                (*sub_type)	= toupper(ptr[i]);
458635682da6daf370cdba78511b917e166f0b6dbecSteve Pfetsch        }
459635682da6daf370cdba78511b917e166f0b6dbecSteve Pfetsch    }
460635682da6daf370cdba78511b917e166f0b6dbecSteve Pfetsch
461635682da6daf370cdba78511b917e166f0b6dbecSteve Pfetsch    return 0;
462635682da6daf370cdba78511b917e166f0b6dbecSteve Pfetsch}
463635682da6daf370cdba78511b917e166f0b6dbecSteve Pfetsch
464635682da6daf370cdba78511b917e166f0b6dbecSteve Pfetsch#define ARRAY   'A'
465635682da6daf370cdba78511b917e166f0b6dbecSteve Pfetsch#define STRING  'S'
466635682da6daf370cdba78511b917e166f0b6dbecSteve Pfetsch#define DECIMAL 'D'
467635682da6daf370cdba78511b917e166f0b6dbecSteve Pfetsch#define BINARY  'B'
468635682da6daf370cdba78511b917e166f0b6dbecSteve Pfetsch
469635682da6daf370cdba78511b917e166f0b6dbecSteve Pfetsch#define PS_HEX           0
470635682da6daf370cdba78511b917e166f0b6dbecSteve Pfetsch#define PS_DEC           1
471635682da6daf370cdba78511b917e166f0b6dbecSteve Pfetsch
472635682da6daf370cdba78511b917e166f0b6dbecSteve Pfetschstatic int get_input_format(char *buf, struct ps_entry_type *format)
473635682da6daf370cdba78511b917e166f0b6dbecSteve Pfetsch{
474635682da6daf370cdba78511b917e166f0b6dbecSteve Pfetsch    char *ptr = NULL;
475635682da6daf370cdba78511b917e166f0b6dbecSteve Pfetsch    char type = '\0';
476635682da6daf370cdba78511b917e166f0b6dbecSteve Pfetsch    char sub_type = '\0';
477635682da6daf370cdba78511b917e166f0b6dbecSteve Pfetsch
478635682da6daf370cdba78511b917e166f0b6dbecSteve Pfetsch    format->type = PS_HEX;
479e2440ccce4e310cc64ca4f9feb71c61f3e148e8fMarie Janssen    format->array = true;
480635682da6daf370cdba78511b917e166f0b6dbecSteve Pfetsch
481635682da6daf370cdba78511b917e166f0b6dbecSteve Pfetsch    if (strstr(buf, "[") != buf)
482635682da6daf370cdba78511b917e166f0b6dbecSteve Pfetsch        return 0;
483635682da6daf370cdba78511b917e166f0b6dbecSteve Pfetsch
484635682da6daf370cdba78511b917e166f0b6dbecSteve Pfetsch    ptr = strstr(buf, "]");
485635682da6daf370cdba78511b917e166f0b6dbecSteve Pfetsch    if (!ptr)
486635682da6daf370cdba78511b917e166f0b6dbecSteve Pfetsch        return -EILSEQ;
487635682da6daf370cdba78511b917e166f0b6dbecSteve Pfetsch
488635682da6daf370cdba78511b917e166f0b6dbecSteve Pfetsch    if (get_ps_type(buf, ptr - buf, &type, &sub_type) < 0)
489635682da6daf370cdba78511b917e166f0b6dbecSteve Pfetsch        return -EILSEQ;
490635682da6daf370cdba78511b917e166f0b6dbecSteve Pfetsch
491635682da6daf370cdba78511b917e166f0b6dbecSteve Pfetsch    /* Check is data type is of array */
492635682da6daf370cdba78511b917e166f0b6dbecSteve Pfetsch    if (type == ARRAY || sub_type == ARRAY)
493e2440ccce4e310cc64ca4f9feb71c61f3e148e8fMarie Janssen        format->array = true;
494635682da6daf370cdba78511b917e166f0b6dbecSteve Pfetsch
495635682da6daf370cdba78511b917e166f0b6dbecSteve Pfetsch    if (type == STRING || sub_type == STRING)
496e2440ccce4e310cc64ca4f9feb71c61f3e148e8fMarie Janssen        format->array = false;
497635682da6daf370cdba78511b917e166f0b6dbecSteve Pfetsch
498635682da6daf370cdba78511b917e166f0b6dbecSteve Pfetsch    if (type == DECIMAL || type == BINARY)
499635682da6daf370cdba78511b917e166f0b6dbecSteve Pfetsch        format->type = PS_DEC;
500635682da6daf370cdba78511b917e166f0b6dbecSteve Pfetsch    else
501635682da6daf370cdba78511b917e166f0b6dbecSteve Pfetsch        format->type = PS_HEX;
502635682da6daf370cdba78511b917e166f0b6dbecSteve Pfetsch
503635682da6daf370cdba78511b917e166f0b6dbecSteve Pfetsch    return 0;
504635682da6daf370cdba78511b917e166f0b6dbecSteve Pfetsch}
505635682da6daf370cdba78511b917e166f0b6dbecSteve Pfetsch
506635682da6daf370cdba78511b917e166f0b6dbecSteve Pfetsch
507635682da6daf370cdba78511b917e166f0b6dbecSteve Pfetsch
508635682da6daf370cdba78511b917e166f0b6dbecSteve Pfetsch#define UNDEFINED 0xFFFF
509635682da6daf370cdba78511b917e166f0b6dbecSteve Pfetsch
510635682da6daf370cdba78511b917e166f0b6dbecSteve Pfetschstatic unsigned int read_data_in_section(char *buf, struct ps_entry_type type)
511635682da6daf370cdba78511b917e166f0b6dbecSteve Pfetsch{
512635682da6daf370cdba78511b917e166f0b6dbecSteve Pfetsch    char *ptr = buf;
513635682da6daf370cdba78511b917e166f0b6dbecSteve Pfetsch
514635682da6daf370cdba78511b917e166f0b6dbecSteve Pfetsch    if (!buf)
515635682da6daf370cdba78511b917e166f0b6dbecSteve Pfetsch        return UNDEFINED;
516635682da6daf370cdba78511b917e166f0b6dbecSteve Pfetsch
517635682da6daf370cdba78511b917e166f0b6dbecSteve Pfetsch    if (buf == strstr(buf, "[")) {
518635682da6daf370cdba78511b917e166f0b6dbecSteve Pfetsch        ptr = strstr(buf, "]");
519635682da6daf370cdba78511b917e166f0b6dbecSteve Pfetsch        if (!ptr)
520635682da6daf370cdba78511b917e166f0b6dbecSteve Pfetsch            return UNDEFINED;
521635682da6daf370cdba78511b917e166f0b6dbecSteve Pfetsch
522635682da6daf370cdba78511b917e166f0b6dbecSteve Pfetsch        ptr++;
523635682da6daf370cdba78511b917e166f0b6dbecSteve Pfetsch    }
524635682da6daf370cdba78511b917e166f0b6dbecSteve Pfetsch
525e2440ccce4e310cc64ca4f9feb71c61f3e148e8fMarie Janssen    if (type.type == PS_HEX && type.array != true)
526635682da6daf370cdba78511b917e166f0b6dbecSteve Pfetsch        return strtol(ptr, NULL, 16);
527635682da6daf370cdba78511b917e166f0b6dbecSteve Pfetsch
528635682da6daf370cdba78511b917e166f0b6dbecSteve Pfetsch    return UNDEFINED;
529635682da6daf370cdba78511b917e166f0b6dbecSteve Pfetsch}
530635682da6daf370cdba78511b917e166f0b6dbecSteve Pfetsch
531635682da6daf370cdba78511b917e166f0b6dbecSteve Pfetsch
532635682da6daf370cdba78511b917e166f0b6dbecSteve Pfetsch/* Read PS entries as string, convert and add to Hex array */
533635682da6daf370cdba78511b917e166f0b6dbecSteve Pfetschstatic void update_tag_data(struct ps_cfg_entry *tag,
534635682da6daf370cdba78511b917e166f0b6dbecSteve Pfetsch    struct tag_info *info, const char *ptr)
535635682da6daf370cdba78511b917e166f0b6dbecSteve Pfetsch{
536635682da6daf370cdba78511b917e166f0b6dbecSteve Pfetsch    char buf[3];
537635682da6daf370cdba78511b917e166f0b6dbecSteve Pfetsch
538635682da6daf370cdba78511b917e166f0b6dbecSteve Pfetsch    buf[2] = '\0';
539635682da6daf370cdba78511b917e166f0b6dbecSteve Pfetsch
540635682da6daf370cdba78511b917e166f0b6dbecSteve Pfetsch    strlcpy(buf, &ptr[info->char_cnt],sizeof(buf));
541635682da6daf370cdba78511b917e166f0b6dbecSteve Pfetsch    tag->data[info->byte_count] = strtol(buf, NULL, 16);
542635682da6daf370cdba78511b917e166f0b6dbecSteve Pfetsch    info->char_cnt += 3;
543635682da6daf370cdba78511b917e166f0b6dbecSteve Pfetsch    info->byte_count++;
544635682da6daf370cdba78511b917e166f0b6dbecSteve Pfetsch
545635682da6daf370cdba78511b917e166f0b6dbecSteve Pfetsch    strlcpy(buf, &ptr[info->char_cnt], sizeof(buf));
546635682da6daf370cdba78511b917e166f0b6dbecSteve Pfetsch    tag->data[info->byte_count] = strtol(buf, NULL, 16);
547635682da6daf370cdba78511b917e166f0b6dbecSteve Pfetsch    info->char_cnt += 3;
548635682da6daf370cdba78511b917e166f0b6dbecSteve Pfetsch    info->byte_count++;
549635682da6daf370cdba78511b917e166f0b6dbecSteve Pfetsch}
550635682da6daf370cdba78511b917e166f0b6dbecSteve Pfetsch
551635682da6daf370cdba78511b917e166f0b6dbecSteve Pfetschstatic inline int update_char_count(const char *buf)
552635682da6daf370cdba78511b917e166f0b6dbecSteve Pfetsch{
553635682da6daf370cdba78511b917e166f0b6dbecSteve Pfetsch    char *end_ptr;
554635682da6daf370cdba78511b917e166f0b6dbecSteve Pfetsch
555635682da6daf370cdba78511b917e166f0b6dbecSteve Pfetsch    if (strstr(buf, "[") == buf) {
556635682da6daf370cdba78511b917e166f0b6dbecSteve Pfetsch        end_ptr = strstr(buf, "]");
557635682da6daf370cdba78511b917e166f0b6dbecSteve Pfetsch        if (!end_ptr)
558635682da6daf370cdba78511b917e166f0b6dbecSteve Pfetsch            return 0;
559635682da6daf370cdba78511b917e166f0b6dbecSteve Pfetsch        else
560635682da6daf370cdba78511b917e166f0b6dbecSteve Pfetsch            return(end_ptr - buf) +	1;
561635682da6daf370cdba78511b917e166f0b6dbecSteve Pfetsch    }
562635682da6daf370cdba78511b917e166f0b6dbecSteve Pfetsch
563635682da6daf370cdba78511b917e166f0b6dbecSteve Pfetsch    return 0;
564635682da6daf370cdba78511b917e166f0b6dbecSteve Pfetsch}
565635682da6daf370cdba78511b917e166f0b6dbecSteve Pfetsch
566635682da6daf370cdba78511b917e166f0b6dbecSteve Pfetsch#define PS_HEX           0
567635682da6daf370cdba78511b917e166f0b6dbecSteve Pfetsch#define PS_DEC           1
568635682da6daf370cdba78511b917e166f0b6dbecSteve Pfetsch
569635682da6daf370cdba78511b917e166f0b6dbecSteve Pfetschstatic int ath_parse_ps(FILE *stream)
570635682da6daf370cdba78511b917e166f0b6dbecSteve Pfetsch{
571635682da6daf370cdba78511b917e166f0b6dbecSteve Pfetsch    char buf[LINE_SIZE_MAX + 1];
572635682da6daf370cdba78511b917e166f0b6dbecSteve Pfetsch    char *ptr;
573635682da6daf370cdba78511b917e166f0b6dbecSteve Pfetsch    uint8_t tag_cnt = 0;
574635682da6daf370cdba78511b917e166f0b6dbecSteve Pfetsch    int16_t byte_count = 0;
575635682da6daf370cdba78511b917e166f0b6dbecSteve Pfetsch    struct ps_entry_type format;
576635682da6daf370cdba78511b917e166f0b6dbecSteve Pfetsch    struct tag_info status = { 0, 0, 0, 0};
577635682da6daf370cdba78511b917e166f0b6dbecSteve Pfetsch
578635682da6daf370cdba78511b917e166f0b6dbecSteve Pfetsch    do {
579635682da6daf370cdba78511b917e166f0b6dbecSteve Pfetsch        int read_count;
580635682da6daf370cdba78511b917e166f0b6dbecSteve Pfetsch        struct ps_cfg_entry *tag;
581635682da6daf370cdba78511b917e166f0b6dbecSteve Pfetsch
582635682da6daf370cdba78511b917e166f0b6dbecSteve Pfetsch        ptr = fgets(buf, LINE_SIZE_MAX, stream);
583635682da6daf370cdba78511b917e166f0b6dbecSteve Pfetsch        if (!ptr)
584635682da6daf370cdba78511b917e166f0b6dbecSteve Pfetsch            break;
585635682da6daf370cdba78511b917e166f0b6dbecSteve Pfetsch
586635682da6daf370cdba78511b917e166f0b6dbecSteve Pfetsch        __skip_space(ptr);
587635682da6daf370cdba78511b917e166f0b6dbecSteve Pfetsch        if (__check_comment(ptr))
588635682da6daf370cdba78511b917e166f0b6dbecSteve Pfetsch            continue;
589635682da6daf370cdba78511b917e166f0b6dbecSteve Pfetsch
590635682da6daf370cdba78511b917e166f0b6dbecSteve Pfetsch        /* Lines with a '#' will be followed by new PS entry */
591635682da6daf370cdba78511b917e166f0b6dbecSteve Pfetsch        if (ptr == strstr(ptr, "#")) {
592635682da6daf370cdba78511b917e166f0b6dbecSteve Pfetsch            if (status.section != PS_UNDEF) {
593635682da6daf370cdba78511b917e166f0b6dbecSteve Pfetsch                return -EILSEQ;
594635682da6daf370cdba78511b917e166f0b6dbecSteve Pfetsch            } else {
595635682da6daf370cdba78511b917e166f0b6dbecSteve Pfetsch                status.section = PS_ID;
596635682da6daf370cdba78511b917e166f0b6dbecSteve Pfetsch                continue;
597635682da6daf370cdba78511b917e166f0b6dbecSteve Pfetsch            }
598635682da6daf370cdba78511b917e166f0b6dbecSteve Pfetsch        }
599635682da6daf370cdba78511b917e166f0b6dbecSteve Pfetsch
600635682da6daf370cdba78511b917e166f0b6dbecSteve Pfetsch        tag = &ps_list[tag_cnt];
601635682da6daf370cdba78511b917e166f0b6dbecSteve Pfetsch
602635682da6daf370cdba78511b917e166f0b6dbecSteve Pfetsch        switch (status.section) {
603635682da6daf370cdba78511b917e166f0b6dbecSteve Pfetsch            case PS_ID:
604635682da6daf370cdba78511b917e166f0b6dbecSteve Pfetsch                if (get_input_format(ptr, &format) < 0)
605635682da6daf370cdba78511b917e166f0b6dbecSteve Pfetsch                    return -EILSEQ;
606635682da6daf370cdba78511b917e166f0b6dbecSteve Pfetsch
607635682da6daf370cdba78511b917e166f0b6dbecSteve Pfetsch                tag->id = read_data_in_section(ptr, format);
608635682da6daf370cdba78511b917e166f0b6dbecSteve Pfetsch                status.section = PS_LEN;
609635682da6daf370cdba78511b917e166f0b6dbecSteve Pfetsch                break;
610635682da6daf370cdba78511b917e166f0b6dbecSteve Pfetsch
611635682da6daf370cdba78511b917e166f0b6dbecSteve Pfetsch            case PS_LEN:
612635682da6daf370cdba78511b917e166f0b6dbecSteve Pfetsch                if (get_input_format(ptr, &format) < 0)
613635682da6daf370cdba78511b917e166f0b6dbecSteve Pfetsch                    return -EILSEQ;
614635682da6daf370cdba78511b917e166f0b6dbecSteve Pfetsch
615635682da6daf370cdba78511b917e166f0b6dbecSteve Pfetsch                byte_count = read_data_in_section(ptr, format);
616635682da6daf370cdba78511b917e166f0b6dbecSteve Pfetsch                if (byte_count > PS_MAX_LEN)
617635682da6daf370cdba78511b917e166f0b6dbecSteve Pfetsch                    return -EILSEQ;
618635682da6daf370cdba78511b917e166f0b6dbecSteve Pfetsch
619635682da6daf370cdba78511b917e166f0b6dbecSteve Pfetsch                tag->len = byte_count;
620635682da6daf370cdba78511b917e166f0b6dbecSteve Pfetsch                tag->data = (uint8_t *)malloc(byte_count);
621635682da6daf370cdba78511b917e166f0b6dbecSteve Pfetsch
622635682da6daf370cdba78511b917e166f0b6dbecSteve Pfetsch                status.section = PS_DATA;
623635682da6daf370cdba78511b917e166f0b6dbecSteve Pfetsch                status.line_count = 0;
624635682da6daf370cdba78511b917e166f0b6dbecSteve Pfetsch                break;
625635682da6daf370cdba78511b917e166f0b6dbecSteve Pfetsch
626635682da6daf370cdba78511b917e166f0b6dbecSteve Pfetsch            case PS_DATA:
627635682da6daf370cdba78511b917e166f0b6dbecSteve Pfetsch            if (status.line_count == 0)
628635682da6daf370cdba78511b917e166f0b6dbecSteve Pfetsch                if (get_input_format(ptr, &format) < 0)
629635682da6daf370cdba78511b917e166f0b6dbecSteve Pfetsch                    return -EILSEQ;
630635682da6daf370cdba78511b917e166f0b6dbecSteve Pfetsch
631635682da6daf370cdba78511b917e166f0b6dbecSteve Pfetsch            __skip_space(ptr);
632635682da6daf370cdba78511b917e166f0b6dbecSteve Pfetsch
633635682da6daf370cdba78511b917e166f0b6dbecSteve Pfetsch            status.char_cnt = update_char_count(ptr);
634635682da6daf370cdba78511b917e166f0b6dbecSteve Pfetsch
635635682da6daf370cdba78511b917e166f0b6dbecSteve Pfetsch            read_count = (byte_count > ENTRY_PER_LINE) ?
636635682da6daf370cdba78511b917e166f0b6dbecSteve Pfetsch            ENTRY_PER_LINE : byte_count;
637635682da6daf370cdba78511b917e166f0b6dbecSteve Pfetsch
638e2440ccce4e310cc64ca4f9feb71c61f3e148e8fMarie Janssen            if (format.type == PS_HEX && format.array == true) {
639635682da6daf370cdba78511b917e166f0b6dbecSteve Pfetsch                while (read_count > 0) {
640635682da6daf370cdba78511b917e166f0b6dbecSteve Pfetsch                    update_tag_data(tag, &status, ptr);
641635682da6daf370cdba78511b917e166f0b6dbecSteve Pfetsch                    read_count -= 2;
642635682da6daf370cdba78511b917e166f0b6dbecSteve Pfetsch                }
643635682da6daf370cdba78511b917e166f0b6dbecSteve Pfetsch
644635682da6daf370cdba78511b917e166f0b6dbecSteve Pfetsch                if (byte_count > ENTRY_PER_LINE)
645635682da6daf370cdba78511b917e166f0b6dbecSteve Pfetsch                    byte_count -= ENTRY_PER_LINE;
646635682da6daf370cdba78511b917e166f0b6dbecSteve Pfetsch                else
647635682da6daf370cdba78511b917e166f0b6dbecSteve Pfetsch                    byte_count = 0;
648635682da6daf370cdba78511b917e166f0b6dbecSteve Pfetsch            }
649635682da6daf370cdba78511b917e166f0b6dbecSteve Pfetsch
650635682da6daf370cdba78511b917e166f0b6dbecSteve Pfetsch            status.line_count++;
651635682da6daf370cdba78511b917e166f0b6dbecSteve Pfetsch
652635682da6daf370cdba78511b917e166f0b6dbecSteve Pfetsch            if (byte_count == 0)
653635682da6daf370cdba78511b917e166f0b6dbecSteve Pfetsch                memset(&status, 0x00, sizeof(struct tag_info));
654635682da6daf370cdba78511b917e166f0b6dbecSteve Pfetsch
655635682da6daf370cdba78511b917e166f0b6dbecSteve Pfetsch            if (status.section == PS_UNDEF)
656635682da6daf370cdba78511b917e166f0b6dbecSteve Pfetsch                tag_cnt++;
657635682da6daf370cdba78511b917e166f0b6dbecSteve Pfetsch
658635682da6daf370cdba78511b917e166f0b6dbecSteve Pfetsch            if (tag_cnt == MAX_TAGS)
659635682da6daf370cdba78511b917e166f0b6dbecSteve Pfetsch                return -EILSEQ;
660635682da6daf370cdba78511b917e166f0b6dbecSteve Pfetsch            break;
661635682da6daf370cdba78511b917e166f0b6dbecSteve Pfetsch        }
662635682da6daf370cdba78511b917e166f0b6dbecSteve Pfetsch    } while (ptr);
663635682da6daf370cdba78511b917e166f0b6dbecSteve Pfetsch
664635682da6daf370cdba78511b917e166f0b6dbecSteve Pfetsch    return tag_cnt;
665635682da6daf370cdba78511b917e166f0b6dbecSteve Pfetsch}
666635682da6daf370cdba78511b917e166f0b6dbecSteve Pfetsch
667635682da6daf370cdba78511b917e166f0b6dbecSteve Pfetsch#define PS_RAM_SIZE 2048
668635682da6daf370cdba78511b917e166f0b6dbecSteve Pfetsch
669635682da6daf370cdba78511b917e166f0b6dbecSteve Pfetschstatic int ps_config_download(int fd, int tag_count)
670635682da6daf370cdba78511b917e166f0b6dbecSteve Pfetsch{
671635682da6daf370cdba78511b917e166f0b6dbecSteve Pfetsch    if (write_ps_cmd(fd, PS_RESET, PS_RAM_SIZE) < 0)
672635682da6daf370cdba78511b917e166f0b6dbecSteve Pfetsch        return -1;
673635682da6daf370cdba78511b917e166f0b6dbecSteve Pfetsch
674635682da6daf370cdba78511b917e166f0b6dbecSteve Pfetsch    if (tag_count > 0)
675635682da6daf370cdba78511b917e166f0b6dbecSteve Pfetsch        if (write_ps_cmd(fd, PS_WRITE, tag_count) < 0)
676635682da6daf370cdba78511b917e166f0b6dbecSteve Pfetsch            return -1;
677635682da6daf370cdba78511b917e166f0b6dbecSteve Pfetsch    return 0;
678635682da6daf370cdba78511b917e166f0b6dbecSteve Pfetsch}
679635682da6daf370cdba78511b917e166f0b6dbecSteve Pfetsch
680635682da6daf370cdba78511b917e166f0b6dbecSteve Pfetschstatic int write_bdaddr(int pConfig, char *bdaddr)
681635682da6daf370cdba78511b917e166f0b6dbecSteve Pfetsch{
682635682da6daf370cdba78511b917e166f0b6dbecSteve Pfetsch    uint8_t *event;
683635682da6daf370cdba78511b917e166f0b6dbecSteve Pfetsch    int err;
684635682da6daf370cdba78511b917e166f0b6dbecSteve Pfetsch    uint8_t cmd[13];
685635682da6daf370cdba78511b917e166f0b6dbecSteve Pfetsch    uint8_t *ptr = cmd;
686635682da6daf370cdba78511b917e166f0b6dbecSteve Pfetsch    hci_command_hdr *ch = (void *)cmd;
687635682da6daf370cdba78511b917e166f0b6dbecSteve Pfetsch
688635682da6daf370cdba78511b917e166f0b6dbecSteve Pfetsch    memset(cmd, 0, sizeof(cmd));
689635682da6daf370cdba78511b917e166f0b6dbecSteve Pfetsch
690635682da6daf370cdba78511b917e166f0b6dbecSteve Pfetsch    ch->opcode = htobs(cmd_opcode_pack(HCI_VENDOR_CMD_OGF,
691635682da6daf370cdba78511b917e166f0b6dbecSteve Pfetsch        HCI_PS_CMD_OCF));
692635682da6daf370cdba78511b917e166f0b6dbecSteve Pfetsch    ch->plen = 10;
693635682da6daf370cdba78511b917e166f0b6dbecSteve Pfetsch    ptr += HCI_COMMAND_HDR_SIZE;
694635682da6daf370cdba78511b917e166f0b6dbecSteve Pfetsch
695635682da6daf370cdba78511b917e166f0b6dbecSteve Pfetsch    ptr[0] = 0x01;
696635682da6daf370cdba78511b917e166f0b6dbecSteve Pfetsch    ptr[1] = 0x01;
697635682da6daf370cdba78511b917e166f0b6dbecSteve Pfetsch    ptr[2] = 0x00;
698635682da6daf370cdba78511b917e166f0b6dbecSteve Pfetsch    ptr[3] = 0x06;
699635682da6daf370cdba78511b917e166f0b6dbecSteve Pfetsch
700635682da6daf370cdba78511b917e166f0b6dbecSteve Pfetsch    convert_bdaddr(bdaddr, (char *)&ptr[4]);
701635682da6daf370cdba78511b917e166f0b6dbecSteve Pfetsch
702635682da6daf370cdba78511b917e166f0b6dbecSteve Pfetsch    err = send_hci_cmd_sync(pConfig, cmd, sizeof(cmd), &event);
703635682da6daf370cdba78511b917e166f0b6dbecSteve Pfetsch    if (err < 0)
704635682da6daf370cdba78511b917e166f0b6dbecSteve Pfetsch        return err;
705635682da6daf370cdba78511b917e166f0b6dbecSteve Pfetsch
706635682da6daf370cdba78511b917e166f0b6dbecSteve Pfetsch    err = read_ps_event(event, HCI_PS_CMD_OCF);
707635682da6daf370cdba78511b917e166f0b6dbecSteve Pfetsch
708635682da6daf370cdba78511b917e166f0b6dbecSteve Pfetsch    free(event);
709635682da6daf370cdba78511b917e166f0b6dbecSteve Pfetsch
710635682da6daf370cdba78511b917e166f0b6dbecSteve Pfetsch    return err;
711635682da6daf370cdba78511b917e166f0b6dbecSteve Pfetsch}
712635682da6daf370cdba78511b917e166f0b6dbecSteve Pfetsch
713635682da6daf370cdba78511b917e166f0b6dbecSteve Pfetschstatic void write_bdaddr_from_file(int rom_version, int fd)
714635682da6daf370cdba78511b917e166f0b6dbecSteve Pfetsch{
715635682da6daf370cdba78511b917e166f0b6dbecSteve Pfetsch    FILE *stream;
716635682da6daf370cdba78511b917e166f0b6dbecSteve Pfetsch    char bdaddr[PATH_MAX];
717635682da6daf370cdba78511b917e166f0b6dbecSteve Pfetsch    char bdaddr_file[PATH_MAX];
718635682da6daf370cdba78511b917e166f0b6dbecSteve Pfetsch
719635682da6daf370cdba78511b917e166f0b6dbecSteve Pfetsch    snprintf(bdaddr_file, MAXPATHLEN, "%s%x/%s",
720635682da6daf370cdba78511b917e166f0b6dbecSteve Pfetsch    FW_PATH, rom_version, BDADDR_FILE);
721635682da6daf370cdba78511b917e166f0b6dbecSteve Pfetsch
722635682da6daf370cdba78511b917e166f0b6dbecSteve Pfetsch    stream = fopen(bdaddr_file, "r");
723635682da6daf370cdba78511b917e166f0b6dbecSteve Pfetsch    if (!stream)
724635682da6daf370cdba78511b917e166f0b6dbecSteve Pfetsch       return;
725635682da6daf370cdba78511b917e166f0b6dbecSteve Pfetsch
726635682da6daf370cdba78511b917e166f0b6dbecSteve Pfetsch    if (fgets(bdaddr, PATH_MAX - 1, stream))
727635682da6daf370cdba78511b917e166f0b6dbecSteve Pfetsch        write_bdaddr(fd, bdaddr);
728635682da6daf370cdba78511b917e166f0b6dbecSteve Pfetsch
729635682da6daf370cdba78511b917e166f0b6dbecSteve Pfetsch    fclose(stream);
730635682da6daf370cdba78511b917e166f0b6dbecSteve Pfetsch}
731635682da6daf370cdba78511b917e166f0b6dbecSteve Pfetsch
732635682da6daf370cdba78511b917e166f0b6dbecSteve Pfetsch#define HCI_EVT_CMD_CMPL_OPCODE                 3
733635682da6daf370cdba78511b917e166f0b6dbecSteve Pfetsch#define HCI_EVT_CMD_CMPL_STATUS_RET_BYTE        5
734635682da6daf370cdba78511b917e166f0b6dbecSteve Pfetsch
735635682da6daf370cdba78511b917e166f0b6dbecSteve Pfetschvoid baswap(bdaddr_t *dst, const bdaddr_t *src)
736635682da6daf370cdba78511b917e166f0b6dbecSteve Pfetsch{
737635682da6daf370cdba78511b917e166f0b6dbecSteve Pfetsch    register unsigned char *d = (unsigned char *) dst;
738635682da6daf370cdba78511b917e166f0b6dbecSteve Pfetsch    register const unsigned char *s = (const unsigned char *) src;
739635682da6daf370cdba78511b917e166f0b6dbecSteve Pfetsch    register int i;
740635682da6daf370cdba78511b917e166f0b6dbecSteve Pfetsch    for (i = 0; i < 6; i++)
741635682da6daf370cdba78511b917e166f0b6dbecSteve Pfetsch        d[i] = s[5-i];
742635682da6daf370cdba78511b917e166f0b6dbecSteve Pfetsch}
743635682da6daf370cdba78511b917e166f0b6dbecSteve Pfetsch
744635682da6daf370cdba78511b917e166f0b6dbecSteve Pfetsch
745635682da6daf370cdba78511b917e166f0b6dbecSteve Pfetschint str2ba(const char *str, bdaddr_t *ba)
746635682da6daf370cdba78511b917e166f0b6dbecSteve Pfetsch{
747635682da6daf370cdba78511b917e166f0b6dbecSteve Pfetsch    uint8_t b[6];
748635682da6daf370cdba78511b917e166f0b6dbecSteve Pfetsch    const char *ptr = str;
749635682da6daf370cdba78511b917e166f0b6dbecSteve Pfetsch    int i;
750635682da6daf370cdba78511b917e166f0b6dbecSteve Pfetsch
751635682da6daf370cdba78511b917e166f0b6dbecSteve Pfetsch    for (i = 0; i < 6; i++) {
752635682da6daf370cdba78511b917e166f0b6dbecSteve Pfetsch        b[i] = (uint8_t) strtol(ptr, NULL, 16);
753635682da6daf370cdba78511b917e166f0b6dbecSteve Pfetsch        ptr = strchr(ptr, ':');
754635682da6daf370cdba78511b917e166f0b6dbecSteve Pfetsch        if (i != 5 && !ptr)
755635682da6daf370cdba78511b917e166f0b6dbecSteve Pfetsch            ptr = ":00:00:00:00:00";
756635682da6daf370cdba78511b917e166f0b6dbecSteve Pfetsch        ptr++;
757635682da6daf370cdba78511b917e166f0b6dbecSteve Pfetsch    }
758635682da6daf370cdba78511b917e166f0b6dbecSteve Pfetsch    baswap(ba, (bdaddr_t *) b);
759635682da6daf370cdba78511b917e166f0b6dbecSteve Pfetsch    return 0;
760635682da6daf370cdba78511b917e166f0b6dbecSteve Pfetsch}
761635682da6daf370cdba78511b917e166f0b6dbecSteve Pfetsch
762635682da6daf370cdba78511b917e166f0b6dbecSteve Pfetsch#define DEV_REGISTER      0x4FFC
763635682da6daf370cdba78511b917e166f0b6dbecSteve Pfetsch#define GET_DEV_TYPE_OCF  0x05
764635682da6daf370cdba78511b917e166f0b6dbecSteve Pfetsch
765635682da6daf370cdba78511b917e166f0b6dbecSteve Pfetschstatic int get_device_type(int dev, uint32_t *code)
766635682da6daf370cdba78511b917e166f0b6dbecSteve Pfetsch{
767635682da6daf370cdba78511b917e166f0b6dbecSteve Pfetsch    uint8_t cmd[8] = {0};
768635682da6daf370cdba78511b917e166f0b6dbecSteve Pfetsch    uint8_t *event;
769635682da6daf370cdba78511b917e166f0b6dbecSteve Pfetsch    uint32_t reg;
770635682da6daf370cdba78511b917e166f0b6dbecSteve Pfetsch    int err;
771635682da6daf370cdba78511b917e166f0b6dbecSteve Pfetsch    uint8_t *ptr = cmd;
772635682da6daf370cdba78511b917e166f0b6dbecSteve Pfetsch    hci_command_hdr *ch = (void *)cmd;
773635682da6daf370cdba78511b917e166f0b6dbecSteve Pfetsch
774635682da6daf370cdba78511b917e166f0b6dbecSteve Pfetsch    ch->opcode = htobs(cmd_opcode_pack(HCI_VENDOR_CMD_OGF,
775635682da6daf370cdba78511b917e166f0b6dbecSteve Pfetsch        GET_DEV_TYPE_OCF));
776635682da6daf370cdba78511b917e166f0b6dbecSteve Pfetsch    ch->plen = 5;
777635682da6daf370cdba78511b917e166f0b6dbecSteve Pfetsch    ptr += HCI_COMMAND_HDR_SIZE;
778635682da6daf370cdba78511b917e166f0b6dbecSteve Pfetsch
779635682da6daf370cdba78511b917e166f0b6dbecSteve Pfetsch    ptr[0] = (uint8_t)DEV_REGISTER;
780635682da6daf370cdba78511b917e166f0b6dbecSteve Pfetsch    ptr[1] = (uint8_t)DEV_REGISTER >> 8;
781635682da6daf370cdba78511b917e166f0b6dbecSteve Pfetsch    ptr[2] = (uint8_t)DEV_REGISTER >> 16;
782635682da6daf370cdba78511b917e166f0b6dbecSteve Pfetsch    ptr[3] = (uint8_t)DEV_REGISTER >> 24;
783635682da6daf370cdba78511b917e166f0b6dbecSteve Pfetsch    ptr[4] = 0x04;
784635682da6daf370cdba78511b917e166f0b6dbecSteve Pfetsch
785635682da6daf370cdba78511b917e166f0b6dbecSteve Pfetsch    err = send_hci_cmd_sync(dev, cmd, sizeof(cmd), &event);
786635682da6daf370cdba78511b917e166f0b6dbecSteve Pfetsch    if (err < 0)
787635682da6daf370cdba78511b917e166f0b6dbecSteve Pfetsch        return err;
788635682da6daf370cdba78511b917e166f0b6dbecSteve Pfetsch
789635682da6daf370cdba78511b917e166f0b6dbecSteve Pfetsch    err = read_ps_event(event, GET_DEV_TYPE_OCF);
790635682da6daf370cdba78511b917e166f0b6dbecSteve Pfetsch    if (err < 0)
791635682da6daf370cdba78511b917e166f0b6dbecSteve Pfetsch        goto cleanup;
792635682da6daf370cdba78511b917e166f0b6dbecSteve Pfetsch
793635682da6daf370cdba78511b917e166f0b6dbecSteve Pfetsch    reg = event[10];
794635682da6daf370cdba78511b917e166f0b6dbecSteve Pfetsch    reg = (reg << 8) | event[9];
795635682da6daf370cdba78511b917e166f0b6dbecSteve Pfetsch    reg = (reg << 8) | event[8];
796635682da6daf370cdba78511b917e166f0b6dbecSteve Pfetsch    reg = (reg << 8) | event[7];
797635682da6daf370cdba78511b917e166f0b6dbecSteve Pfetsch    *code = reg;
798635682da6daf370cdba78511b917e166f0b6dbecSteve Pfetsch
799635682da6daf370cdba78511b917e166f0b6dbecSteve Pfetschcleanup:
800635682da6daf370cdba78511b917e166f0b6dbecSteve Pfetsch    free(event);
801635682da6daf370cdba78511b917e166f0b6dbecSteve Pfetsch
802635682da6daf370cdba78511b917e166f0b6dbecSteve Pfetsch    return err;
803635682da6daf370cdba78511b917e166f0b6dbecSteve Pfetsch}
804635682da6daf370cdba78511b917e166f0b6dbecSteve Pfetsch
805635682da6daf370cdba78511b917e166f0b6dbecSteve Pfetsch#define GET_VERSION_OCF 0x1E
806635682da6daf370cdba78511b917e166f0b6dbecSteve Pfetsch
807635682da6daf370cdba78511b917e166f0b6dbecSteve Pfetschstatic int read_ath3k_version(int pConfig, uint32_t *rom_version,
808635682da6daf370cdba78511b917e166f0b6dbecSteve Pfetsch    uint32_t *build_version)
809635682da6daf370cdba78511b917e166f0b6dbecSteve Pfetsch{
810635682da6daf370cdba78511b917e166f0b6dbecSteve Pfetsch    uint8_t cmd[3] = {0};
811635682da6daf370cdba78511b917e166f0b6dbecSteve Pfetsch    uint8_t *event;
812635682da6daf370cdba78511b917e166f0b6dbecSteve Pfetsch    int err;
813635682da6daf370cdba78511b917e166f0b6dbecSteve Pfetsch    int status;
814635682da6daf370cdba78511b917e166f0b6dbecSteve Pfetsch    hci_command_hdr *ch = (void *)cmd;
815635682da6daf370cdba78511b917e166f0b6dbecSteve Pfetsch
816635682da6daf370cdba78511b917e166f0b6dbecSteve Pfetsch    ch->opcode = htobs(cmd_opcode_pack(HCI_VENDOR_CMD_OGF,
817635682da6daf370cdba78511b917e166f0b6dbecSteve Pfetsch    GET_VERSION_OCF));
818635682da6daf370cdba78511b917e166f0b6dbecSteve Pfetsch    ch->plen = 0;
819635682da6daf370cdba78511b917e166f0b6dbecSteve Pfetsch
820635682da6daf370cdba78511b917e166f0b6dbecSteve Pfetsch    err = send_hci_cmd_sync(pConfig, cmd, sizeof(cmd), &event);
821635682da6daf370cdba78511b917e166f0b6dbecSteve Pfetsch    if (err < 0)
822635682da6daf370cdba78511b917e166f0b6dbecSteve Pfetsch        return err;
823635682da6daf370cdba78511b917e166f0b6dbecSteve Pfetsch
824635682da6daf370cdba78511b917e166f0b6dbecSteve Pfetsch    err = read_ps_event(event, GET_VERSION_OCF);
825635682da6daf370cdba78511b917e166f0b6dbecSteve Pfetsch    if (err < 0)
826635682da6daf370cdba78511b917e166f0b6dbecSteve Pfetsch        goto cleanup;
827635682da6daf370cdba78511b917e166f0b6dbecSteve Pfetsch
828635682da6daf370cdba78511b917e166f0b6dbecSteve Pfetsch    status = event[10];
829635682da6daf370cdba78511b917e166f0b6dbecSteve Pfetsch    status = (status << 8) | event[9];
830635682da6daf370cdba78511b917e166f0b6dbecSteve Pfetsch    status = (status << 8) | event[8];
831635682da6daf370cdba78511b917e166f0b6dbecSteve Pfetsch    status = (status << 8) | event[7];
832635682da6daf370cdba78511b917e166f0b6dbecSteve Pfetsch    *rom_version = status;
833635682da6daf370cdba78511b917e166f0b6dbecSteve Pfetsch
834635682da6daf370cdba78511b917e166f0b6dbecSteve Pfetsch    status = event[14];
835635682da6daf370cdba78511b917e166f0b6dbecSteve Pfetsch    status = (status << 8) | event[13];
836635682da6daf370cdba78511b917e166f0b6dbecSteve Pfetsch    status = (status << 8) | event[12];
837635682da6daf370cdba78511b917e166f0b6dbecSteve Pfetsch    status = (status << 8) | event[11];
838635682da6daf370cdba78511b917e166f0b6dbecSteve Pfetsch    *build_version = status;
839635682da6daf370cdba78511b917e166f0b6dbecSteve Pfetsch
840635682da6daf370cdba78511b917e166f0b6dbecSteve Pfetschcleanup:
841635682da6daf370cdba78511b917e166f0b6dbecSteve Pfetsch    free(event);
842635682da6daf370cdba78511b917e166f0b6dbecSteve Pfetsch
843635682da6daf370cdba78511b917e166f0b6dbecSteve Pfetsch    return err;
844635682da6daf370cdba78511b917e166f0b6dbecSteve Pfetsch}
845635682da6daf370cdba78511b917e166f0b6dbecSteve Pfetsch
846635682da6daf370cdba78511b917e166f0b6dbecSteve Pfetsch#define VERIFY_CRC   9
847635682da6daf370cdba78511b917e166f0b6dbecSteve Pfetsch#define PS_REGION    1
848635682da6daf370cdba78511b917e166f0b6dbecSteve Pfetsch#define PATCH_REGION 2
849635682da6daf370cdba78511b917e166f0b6dbecSteve Pfetsch
850635682da6daf370cdba78511b917e166f0b6dbecSteve Pfetschstatic int get_ath3k_crc(int dev)
851635682da6daf370cdba78511b917e166f0b6dbecSteve Pfetsch{
852635682da6daf370cdba78511b917e166f0b6dbecSteve Pfetsch    uint8_t cmd[7] = {0};
853635682da6daf370cdba78511b917e166f0b6dbecSteve Pfetsch    uint8_t *event;
854635682da6daf370cdba78511b917e166f0b6dbecSteve Pfetsch    int err;
855635682da6daf370cdba78511b917e166f0b6dbecSteve Pfetsch
856635682da6daf370cdba78511b917e166f0b6dbecSteve Pfetsch    load_hci_ps_hdr(cmd, VERIFY_CRC, 0, PS_REGION | PATCH_REGION);
857635682da6daf370cdba78511b917e166f0b6dbecSteve Pfetsch
858635682da6daf370cdba78511b917e166f0b6dbecSteve Pfetsch    err = send_hci_cmd_sync(dev, cmd, sizeof(cmd), &event);
859635682da6daf370cdba78511b917e166f0b6dbecSteve Pfetsch    if (err < 0)
860635682da6daf370cdba78511b917e166f0b6dbecSteve Pfetsch        return err;
861635682da6daf370cdba78511b917e166f0b6dbecSteve Pfetsch    /* Send error code if CRC check patched */
862635682da6daf370cdba78511b917e166f0b6dbecSteve Pfetsch    if (read_ps_event(event, HCI_PS_CMD_OCF) >= 0)
863635682da6daf370cdba78511b917e166f0b6dbecSteve Pfetsch        err = -EILSEQ;
864635682da6daf370cdba78511b917e166f0b6dbecSteve Pfetsch
865635682da6daf370cdba78511b917e166f0b6dbecSteve Pfetsch    free(event);
866635682da6daf370cdba78511b917e166f0b6dbecSteve Pfetsch
867635682da6daf370cdba78511b917e166f0b6dbecSteve Pfetsch    return err;
868635682da6daf370cdba78511b917e166f0b6dbecSteve Pfetsch}
869635682da6daf370cdba78511b917e166f0b6dbecSteve Pfetsch
870635682da6daf370cdba78511b917e166f0b6dbecSteve Pfetsch#define SET_PATCH_RAM_ID        0x0D
871635682da6daf370cdba78511b917e166f0b6dbecSteve Pfetsch#define SET_PATCH_RAM_CMD_SIZE  11
872635682da6daf370cdba78511b917e166f0b6dbecSteve Pfetsch#define ADDRESS_LEN             4
873635682da6daf370cdba78511b917e166f0b6dbecSteve Pfetschstatic int set_patch_ram(int dev, char *patch_loc, int len)
874635682da6daf370cdba78511b917e166f0b6dbecSteve Pfetsch{
875635682da6daf370cdba78511b917e166f0b6dbecSteve Pfetsch    int err;
876635682da6daf370cdba78511b917e166f0b6dbecSteve Pfetsch    uint8_t cmd[20] = {0};
877635682da6daf370cdba78511b917e166f0b6dbecSteve Pfetsch    int i, j;
878635682da6daf370cdba78511b917e166f0b6dbecSteve Pfetsch    char loc_byte[3];
879635682da6daf370cdba78511b917e166f0b6dbecSteve Pfetsch    uint8_t *event;
880635682da6daf370cdba78511b917e166f0b6dbecSteve Pfetsch    uint8_t *loc_ptr = &cmd[7];
881635682da6daf370cdba78511b917e166f0b6dbecSteve Pfetsch
882635682da6daf370cdba78511b917e166f0b6dbecSteve Pfetsch    RESERVED(len);
883635682da6daf370cdba78511b917e166f0b6dbecSteve Pfetsch
884635682da6daf370cdba78511b917e166f0b6dbecSteve Pfetsch    if (!patch_loc)
885635682da6daf370cdba78511b917e166f0b6dbecSteve Pfetsch        return -1;
886635682da6daf370cdba78511b917e166f0b6dbecSteve Pfetsch
887635682da6daf370cdba78511b917e166f0b6dbecSteve Pfetsch    loc_byte[2] = '\0';
888635682da6daf370cdba78511b917e166f0b6dbecSteve Pfetsch
889635682da6daf370cdba78511b917e166f0b6dbecSteve Pfetsch    load_hci_ps_hdr(cmd, SET_PATCH_RAM_ID, ADDRESS_LEN, 0);
890635682da6daf370cdba78511b917e166f0b6dbecSteve Pfetsch
891635682da6daf370cdba78511b917e166f0b6dbecSteve Pfetsch    for (i = 0, j = 3; i < 4; i++, j--) {
892635682da6daf370cdba78511b917e166f0b6dbecSteve Pfetsch        loc_byte[0] = patch_loc[0];
893635682da6daf370cdba78511b917e166f0b6dbecSteve Pfetsch        loc_byte[1] = patch_loc[1];
894635682da6daf370cdba78511b917e166f0b6dbecSteve Pfetsch        loc_ptr[j] = strtol(loc_byte, NULL, 16);
895635682da6daf370cdba78511b917e166f0b6dbecSteve Pfetsch        patch_loc += 2;
896635682da6daf370cdba78511b917e166f0b6dbecSteve Pfetsch    }
897635682da6daf370cdba78511b917e166f0b6dbecSteve Pfetsch
898635682da6daf370cdba78511b917e166f0b6dbecSteve Pfetsch    err = send_hci_cmd_sync(dev, cmd, SET_PATCH_RAM_CMD_SIZE, &event);
899635682da6daf370cdba78511b917e166f0b6dbecSteve Pfetsch    if (err < 0)
900635682da6daf370cdba78511b917e166f0b6dbecSteve Pfetsch        return err;
901635682da6daf370cdba78511b917e166f0b6dbecSteve Pfetsch
902635682da6daf370cdba78511b917e166f0b6dbecSteve Pfetsch    err = read_ps_event(event, HCI_PS_CMD_OCF);
903635682da6daf370cdba78511b917e166f0b6dbecSteve Pfetsch
904635682da6daf370cdba78511b917e166f0b6dbecSteve Pfetsch    free(event);
905635682da6daf370cdba78511b917e166f0b6dbecSteve Pfetsch
906635682da6daf370cdba78511b917e166f0b6dbecSteve Pfetsch    return err;
907635682da6daf370cdba78511b917e166f0b6dbecSteve Pfetsch}
908635682da6daf370cdba78511b917e166f0b6dbecSteve Pfetsch
909635682da6daf370cdba78511b917e166f0b6dbecSteve Pfetsch#define PATCH_LOC_KEY    "DA:"
910635682da6daf370cdba78511b917e166f0b6dbecSteve Pfetsch#define PATCH_LOC_STRING_LEN    8
911635682da6daf370cdba78511b917e166f0b6dbecSteve Pfetschstatic int ps_patch_download(int fd, FILE *stream)
912635682da6daf370cdba78511b917e166f0b6dbecSteve Pfetsch{
913635682da6daf370cdba78511b917e166f0b6dbecSteve Pfetsch    char byte[3];
914635682da6daf370cdba78511b917e166f0b6dbecSteve Pfetsch    char ptr[MAX_PATCH_CMD + 1];
915635682da6daf370cdba78511b917e166f0b6dbecSteve Pfetsch    int byte_cnt;
916635682da6daf370cdba78511b917e166f0b6dbecSteve Pfetsch    int patch_count = 0;
917635682da6daf370cdba78511b917e166f0b6dbecSteve Pfetsch    char patch_loc[PATCH_LOC_STRING_LEN + 1];
918635682da6daf370cdba78511b917e166f0b6dbecSteve Pfetsch
919635682da6daf370cdba78511b917e166f0b6dbecSteve Pfetsch    byte[2] = '\0';
920635682da6daf370cdba78511b917e166f0b6dbecSteve Pfetsch
921635682da6daf370cdba78511b917e166f0b6dbecSteve Pfetsch    while (fgets(ptr, MAX_PATCH_CMD, stream)) {
922635682da6daf370cdba78511b917e166f0b6dbecSteve Pfetsch        if (strlen(ptr) <= 1)
923635682da6daf370cdba78511b917e166f0b6dbecSteve Pfetsch            continue;
924635682da6daf370cdba78511b917e166f0b6dbecSteve Pfetsch        else if (strstr(ptr, PATCH_LOC_KEY) == ptr) {
925635682da6daf370cdba78511b917e166f0b6dbecSteve Pfetsch            strlcpy(patch_loc, &ptr[sizeof(PATCH_LOC_KEY) - 1],
926635682da6daf370cdba78511b917e166f0b6dbecSteve Pfetsch                PATCH_LOC_STRING_LEN);
927635682da6daf370cdba78511b917e166f0b6dbecSteve Pfetsch            if (set_patch_ram(fd, patch_loc, sizeof(patch_loc)) < 0)
928635682da6daf370cdba78511b917e166f0b6dbecSteve Pfetsch                return -1;
929635682da6daf370cdba78511b917e166f0b6dbecSteve Pfetsch        } else if (isxdigit(ptr[0]))
930635682da6daf370cdba78511b917e166f0b6dbecSteve Pfetsch            break;
931635682da6daf370cdba78511b917e166f0b6dbecSteve Pfetsch        else
932635682da6daf370cdba78511b917e166f0b6dbecSteve Pfetsch        return -1;
933635682da6daf370cdba78511b917e166f0b6dbecSteve Pfetsch    }
934635682da6daf370cdba78511b917e166f0b6dbecSteve Pfetsch
935635682da6daf370cdba78511b917e166f0b6dbecSteve Pfetsch    byte_cnt = strtol(ptr, NULL, 16);
936635682da6daf370cdba78511b917e166f0b6dbecSteve Pfetsch
937635682da6daf370cdba78511b917e166f0b6dbecSteve Pfetsch    while (byte_cnt > 0) {
938635682da6daf370cdba78511b917e166f0b6dbecSteve Pfetsch        int i;
939635682da6daf370cdba78511b917e166f0b6dbecSteve Pfetsch        uint8_t cmd[HCI_MAX_CMD_SIZE] = {0};
940635682da6daf370cdba78511b917e166f0b6dbecSteve Pfetsch        struct patch_entry patch;
941635682da6daf370cdba78511b917e166f0b6dbecSteve Pfetsch
942635682da6daf370cdba78511b917e166f0b6dbecSteve Pfetsch        if (byte_cnt > MAX_PATCH_CMD)
943635682da6daf370cdba78511b917e166f0b6dbecSteve Pfetsch            patch.len = MAX_PATCH_CMD;
944635682da6daf370cdba78511b917e166f0b6dbecSteve Pfetsch        else
945635682da6daf370cdba78511b917e166f0b6dbecSteve Pfetsch            patch.len = byte_cnt;
946635682da6daf370cdba78511b917e166f0b6dbecSteve Pfetsch
947635682da6daf370cdba78511b917e166f0b6dbecSteve Pfetsch        for (i = 0; i < patch.len; i++) {
948635682da6daf370cdba78511b917e166f0b6dbecSteve Pfetsch            if (!fgets(byte, 3, stream))
949635682da6daf370cdba78511b917e166f0b6dbecSteve Pfetsch                return -1;
950635682da6daf370cdba78511b917e166f0b6dbecSteve Pfetsch
951635682da6daf370cdba78511b917e166f0b6dbecSteve Pfetsch            patch.data[i] = strtoul(byte, NULL, 16);
952635682da6daf370cdba78511b917e166f0b6dbecSteve Pfetsch        }
953635682da6daf370cdba78511b917e166f0b6dbecSteve Pfetsch
954635682da6daf370cdba78511b917e166f0b6dbecSteve Pfetsch        load_hci_ps_hdr(cmd, WRITE_PATCH, patch.len, patch_count);
955635682da6daf370cdba78511b917e166f0b6dbecSteve Pfetsch        memcpy(&cmd[HCI_PS_CMD_HDR_LEN], patch.data, patch.len);
956635682da6daf370cdba78511b917e166f0b6dbecSteve Pfetsch
957635682da6daf370cdba78511b917e166f0b6dbecSteve Pfetsch        if (write_cmd(fd, cmd, patch.len + HCI_PS_CMD_HDR_LEN) < 0)
958635682da6daf370cdba78511b917e166f0b6dbecSteve Pfetsch            return -1;
959635682da6daf370cdba78511b917e166f0b6dbecSteve Pfetsch
960635682da6daf370cdba78511b917e166f0b6dbecSteve Pfetsch        patch_count++;
961635682da6daf370cdba78511b917e166f0b6dbecSteve Pfetsch        byte_cnt = byte_cnt - MAX_PATCH_CMD;
962635682da6daf370cdba78511b917e166f0b6dbecSteve Pfetsch    }
963635682da6daf370cdba78511b917e166f0b6dbecSteve Pfetsch
964635682da6daf370cdba78511b917e166f0b6dbecSteve Pfetsch    if (write_ps_cmd(fd, ENABLE_PATCH, 0) < 0)
965635682da6daf370cdba78511b917e166f0b6dbecSteve Pfetsch        return -1;
966635682da6daf370cdba78511b917e166f0b6dbecSteve Pfetsch
967635682da6daf370cdba78511b917e166f0b6dbecSteve Pfetsch    return patch_count;
968635682da6daf370cdba78511b917e166f0b6dbecSteve Pfetsch}
969635682da6daf370cdba78511b917e166f0b6dbecSteve Pfetsch
970635682da6daf370cdba78511b917e166f0b6dbecSteve Pfetschstatic int ath_ps_download(int fd)
971635682da6daf370cdba78511b917e166f0b6dbecSteve Pfetsch{
972635682da6daf370cdba78511b917e166f0b6dbecSteve Pfetsch    int err = 0;
973635682da6daf370cdba78511b917e166f0b6dbecSteve Pfetsch    int tag_count;
974635682da6daf370cdba78511b917e166f0b6dbecSteve Pfetsch    int patch_count = 0;
975635682da6daf370cdba78511b917e166f0b6dbecSteve Pfetsch    uint32_t rom_version = 0;
976635682da6daf370cdba78511b917e166f0b6dbecSteve Pfetsch    uint32_t build_version = 0;
977635682da6daf370cdba78511b917e166f0b6dbecSteve Pfetsch    uint32_t dev_type = 0;
978635682da6daf370cdba78511b917e166f0b6dbecSteve Pfetsch    char patch_file[PATH_MAX];
979635682da6daf370cdba78511b917e166f0b6dbecSteve Pfetsch    char ps_file[PATH_MAX];
980635682da6daf370cdba78511b917e166f0b6dbecSteve Pfetsch    FILE *stream;
981635682da6daf370cdba78511b917e166f0b6dbecSteve Pfetsch
982635682da6daf370cdba78511b917e166f0b6dbecSteve Pfetsch    /*
983635682da6daf370cdba78511b917e166f0b6dbecSteve Pfetsch    * Verfiy firmware version. depending on it select the PS
984635682da6daf370cdba78511b917e166f0b6dbecSteve Pfetsch    * config file to download.
985635682da6daf370cdba78511b917e166f0b6dbecSteve Pfetsch    */
986635682da6daf370cdba78511b917e166f0b6dbecSteve Pfetsch    if (get_device_type(fd, &dev_type) < 0) {
987635682da6daf370cdba78511b917e166f0b6dbecSteve Pfetsch        err = -EILSEQ;
988635682da6daf370cdba78511b917e166f0b6dbecSteve Pfetsch        goto download_cmplete;
989635682da6daf370cdba78511b917e166f0b6dbecSteve Pfetsch    }
990635682da6daf370cdba78511b917e166f0b6dbecSteve Pfetsch
991635682da6daf370cdba78511b917e166f0b6dbecSteve Pfetsch    if (read_ath3k_version(fd, &rom_version, &build_version) < 0) {
992635682da6daf370cdba78511b917e166f0b6dbecSteve Pfetsch        err = -EILSEQ;
993635682da6daf370cdba78511b917e166f0b6dbecSteve Pfetsch        goto download_cmplete;
994635682da6daf370cdba78511b917e166f0b6dbecSteve Pfetsch    }
995635682da6daf370cdba78511b917e166f0b6dbecSteve Pfetsch
996635682da6daf370cdba78511b917e166f0b6dbecSteve Pfetsch    /* Do not download configuration if CRC passes */
997635682da6daf370cdba78511b917e166f0b6dbecSteve Pfetsch    if (get_ath3k_crc(fd) < 0) {
998635682da6daf370cdba78511b917e166f0b6dbecSteve Pfetsch        err = 0;
999635682da6daf370cdba78511b917e166f0b6dbecSteve Pfetsch        goto download_cmplete;
1000635682da6daf370cdba78511b917e166f0b6dbecSteve Pfetsch    }
1001635682da6daf370cdba78511b917e166f0b6dbecSteve Pfetsch
1002635682da6daf370cdba78511b917e166f0b6dbecSteve Pfetsch    get_ps_file_name(dev_type, rom_version, ps_file);
1003635682da6daf370cdba78511b917e166f0b6dbecSteve Pfetsch    get_patch_file_name(dev_type, rom_version, build_version, patch_file);
1004635682da6daf370cdba78511b917e166f0b6dbecSteve Pfetsch
1005635682da6daf370cdba78511b917e166f0b6dbecSteve Pfetsch    stream = fopen(ps_file, "r");
1006635682da6daf370cdba78511b917e166f0b6dbecSteve Pfetsch    if (!stream) {
1007635682da6daf370cdba78511b917e166f0b6dbecSteve Pfetsch        ALOGI("firmware file open error:%s, ver:%x\n",ps_file, rom_version);
1008635682da6daf370cdba78511b917e166f0b6dbecSteve Pfetsch        if (rom_version == 0x1020201)
1009635682da6daf370cdba78511b917e166f0b6dbecSteve Pfetsch            err = 0;
1010635682da6daf370cdba78511b917e166f0b6dbecSteve Pfetsch        else
1011635682da6daf370cdba78511b917e166f0b6dbecSteve Pfetsch            err	= -EILSEQ;
1012635682da6daf370cdba78511b917e166f0b6dbecSteve Pfetsch        goto download_cmplete;
1013635682da6daf370cdba78511b917e166f0b6dbecSteve Pfetsch    }
1014635682da6daf370cdba78511b917e166f0b6dbecSteve Pfetsch    tag_count = ath_parse_ps(stream);
1015635682da6daf370cdba78511b917e166f0b6dbecSteve Pfetsch
1016635682da6daf370cdba78511b917e166f0b6dbecSteve Pfetsch    fclose(stream);
1017635682da6daf370cdba78511b917e166f0b6dbecSteve Pfetsch
1018635682da6daf370cdba78511b917e166f0b6dbecSteve Pfetsch    if (tag_count < 0) {
1019635682da6daf370cdba78511b917e166f0b6dbecSteve Pfetsch        err = -EILSEQ;
1020635682da6daf370cdba78511b917e166f0b6dbecSteve Pfetsch        goto download_cmplete;
1021635682da6daf370cdba78511b917e166f0b6dbecSteve Pfetsch    }
1022635682da6daf370cdba78511b917e166f0b6dbecSteve Pfetsch
1023635682da6daf370cdba78511b917e166f0b6dbecSteve Pfetsch    /*
1024635682da6daf370cdba78511b917e166f0b6dbecSteve Pfetsch    * It is not necessary that Patch file be available,
1025635682da6daf370cdba78511b917e166f0b6dbecSteve Pfetsch    * continue with PS Operations if patch file is not available.
1026635682da6daf370cdba78511b917e166f0b6dbecSteve Pfetsch    */
1027635682da6daf370cdba78511b917e166f0b6dbecSteve Pfetsch    if (patch_file[0] == '\0')
1028635682da6daf370cdba78511b917e166f0b6dbecSteve Pfetsch        err = 0;
1029635682da6daf370cdba78511b917e166f0b6dbecSteve Pfetsch
1030635682da6daf370cdba78511b917e166f0b6dbecSteve Pfetsch    stream = fopen(patch_file, "r");
1031635682da6daf370cdba78511b917e166f0b6dbecSteve Pfetsch    if (!stream)
1032635682da6daf370cdba78511b917e166f0b6dbecSteve Pfetsch        err = 0;
1033635682da6daf370cdba78511b917e166f0b6dbecSteve Pfetsch    else {
1034635682da6daf370cdba78511b917e166f0b6dbecSteve Pfetsch        patch_count = ps_patch_download(fd, stream);
1035635682da6daf370cdba78511b917e166f0b6dbecSteve Pfetsch        fclose(stream);
1036635682da6daf370cdba78511b917e166f0b6dbecSteve Pfetsch
1037635682da6daf370cdba78511b917e166f0b6dbecSteve Pfetsch        if (patch_count < 0) {
1038635682da6daf370cdba78511b917e166f0b6dbecSteve Pfetsch            err = -EILSEQ;
1039635682da6daf370cdba78511b917e166f0b6dbecSteve Pfetsch            goto download_cmplete;
1040635682da6daf370cdba78511b917e166f0b6dbecSteve Pfetsch        }
1041635682da6daf370cdba78511b917e166f0b6dbecSteve Pfetsch    }
1042635682da6daf370cdba78511b917e166f0b6dbecSteve Pfetsch
1043635682da6daf370cdba78511b917e166f0b6dbecSteve Pfetsch    err = ps_config_download(fd, tag_count);
1044635682da6daf370cdba78511b917e166f0b6dbecSteve Pfetsch
1045635682da6daf370cdba78511b917e166f0b6dbecSteve Pfetschdownload_cmplete:
1046635682da6daf370cdba78511b917e166f0b6dbecSteve Pfetsch    if (!err)
1047635682da6daf370cdba78511b917e166f0b6dbecSteve Pfetsch        write_bdaddr_from_file(rom_version, fd);
1048635682da6daf370cdba78511b917e166f0b6dbecSteve Pfetsch
1049635682da6daf370cdba78511b917e166f0b6dbecSteve Pfetsch    return err;
1050635682da6daf370cdba78511b917e166f0b6dbecSteve Pfetsch}
1051635682da6daf370cdba78511b917e166f0b6dbecSteve Pfetsch
1052635682da6daf370cdba78511b917e166f0b6dbecSteve Pfetschint ath3k_init(int fd, int speed, int init_speed, char *bdaddr, struct termios *ti)
1053635682da6daf370cdba78511b917e166f0b6dbecSteve Pfetsch{
1054635682da6daf370cdba78511b917e166f0b6dbecSteve Pfetsch    ALOGI(" %s ", __FUNCTION__);
1055635682da6daf370cdba78511b917e166f0b6dbecSteve Pfetsch
1056635682da6daf370cdba78511b917e166f0b6dbecSteve Pfetsch    int r;
1057635682da6daf370cdba78511b917e166f0b6dbecSteve Pfetsch    int err = 0;
1058635682da6daf370cdba78511b917e166f0b6dbecSteve Pfetsch    struct timespec tm = { 0, 500000};
1059635682da6daf370cdba78511b917e166f0b6dbecSteve Pfetsch    unsigned char cmd[MAX_CMD_LEN] = {0};
1060635682da6daf370cdba78511b917e166f0b6dbecSteve Pfetsch    unsigned char rsp[HCI_MAX_EVENT_SIZE];
1061635682da6daf370cdba78511b917e166f0b6dbecSteve Pfetsch    unsigned char *ptr = cmd + 1;
1062635682da6daf370cdba78511b917e166f0b6dbecSteve Pfetsch    hci_command_hdr *ch = (void *)ptr;
1063635682da6daf370cdba78511b917e166f0b6dbecSteve Pfetsch    int flags = 0;
1064635682da6daf370cdba78511b917e166f0b6dbecSteve Pfetsch
1065635682da6daf370cdba78511b917e166f0b6dbecSteve Pfetsch    if (ioctl(fd, TIOCMGET, &flags) < 0) {
1066635682da6daf370cdba78511b917e166f0b6dbecSteve Pfetsch        ALOGI("TIOCMGET failed in init\n");
1067635682da6daf370cdba78511b917e166f0b6dbecSteve Pfetsch        return -1;
1068635682da6daf370cdba78511b917e166f0b6dbecSteve Pfetsch    }
1069635682da6daf370cdba78511b917e166f0b6dbecSteve Pfetsch    flags |= TIOCM_RTS;
1070635682da6daf370cdba78511b917e166f0b6dbecSteve Pfetsch    if (ioctl(fd, TIOCMSET, &flags) < 0) {
1071635682da6daf370cdba78511b917e166f0b6dbecSteve Pfetsch        ALOGI("TIOCMSET failed in init: HW Flow-on error\n");
1072635682da6daf370cdba78511b917e166f0b6dbecSteve Pfetsch        return -1;
1073635682da6daf370cdba78511b917e166f0b6dbecSteve Pfetsch    }
1074635682da6daf370cdba78511b917e166f0b6dbecSteve Pfetsch
1075635682da6daf370cdba78511b917e166f0b6dbecSteve Pfetsch    /* set both controller and host baud rate to maximum possible value */
1076635682da6daf370cdba78511b917e166f0b6dbecSteve Pfetsch    err = set_cntrlr_baud(fd, speed);
1077635682da6daf370cdba78511b917e166f0b6dbecSteve Pfetsch    ALOGI("set_cntrlr_baud : ret:%d \n", err);
1078635682da6daf370cdba78511b917e166f0b6dbecSteve Pfetsch    if (err < 0)
1079635682da6daf370cdba78511b917e166f0b6dbecSteve Pfetsch        return err;
1080635682da6daf370cdba78511b917e166f0b6dbecSteve Pfetsch
1081635682da6daf370cdba78511b917e166f0b6dbecSteve Pfetsch    err = set_speed(fd, ti, speed);
1082635682da6daf370cdba78511b917e166f0b6dbecSteve Pfetsch    if (err < 0) {
1083635682da6daf370cdba78511b917e166f0b6dbecSteve Pfetsch        ALOGI("Can't set required baud rate");
1084635682da6daf370cdba78511b917e166f0b6dbecSteve Pfetsch        return err;
1085635682da6daf370cdba78511b917e166f0b6dbecSteve Pfetsch    }
1086635682da6daf370cdba78511b917e166f0b6dbecSteve Pfetsch
1087635682da6daf370cdba78511b917e166f0b6dbecSteve Pfetsch    /* Download PS and patch */
1088635682da6daf370cdba78511b917e166f0b6dbecSteve Pfetsch    r = ath_ps_download(fd);
1089635682da6daf370cdba78511b917e166f0b6dbecSteve Pfetsch    if (r < 0) {
1090635682da6daf370cdba78511b917e166f0b6dbecSteve Pfetsch        ALOGI("Failed to Download configuration");
1091635682da6daf370cdba78511b917e166f0b6dbecSteve Pfetsch        err = -ETIMEDOUT;
1092635682da6daf370cdba78511b917e166f0b6dbecSteve Pfetsch        goto failed;
1093635682da6daf370cdba78511b917e166f0b6dbecSteve Pfetsch    }
1094635682da6daf370cdba78511b917e166f0b6dbecSteve Pfetsch
1095635682da6daf370cdba78511b917e166f0b6dbecSteve Pfetsch    ALOGI("ath_ps_download is done\n");
1096635682da6daf370cdba78511b917e166f0b6dbecSteve Pfetsch
1097635682da6daf370cdba78511b917e166f0b6dbecSteve Pfetsch    cmd[0] = HCI_COMMAND_PKT;
1098635682da6daf370cdba78511b917e166f0b6dbecSteve Pfetsch    /* Write BDADDR */
1099635682da6daf370cdba78511b917e166f0b6dbecSteve Pfetsch    if (bdaddr) {
1100635682da6daf370cdba78511b917e166f0b6dbecSteve Pfetsch        ch->opcode = htobs(cmd_opcode_pack(HCI_VENDOR_CMD_OGF,
1101635682da6daf370cdba78511b917e166f0b6dbecSteve Pfetsch        HCI_PS_CMD_OCF));
1102635682da6daf370cdba78511b917e166f0b6dbecSteve Pfetsch        ch->plen = 10;
1103635682da6daf370cdba78511b917e166f0b6dbecSteve Pfetsch        ptr += HCI_COMMAND_HDR_SIZE;
1104635682da6daf370cdba78511b917e166f0b6dbecSteve Pfetsch
1105635682da6daf370cdba78511b917e166f0b6dbecSteve Pfetsch        ptr[0] = 0x01;
1106635682da6daf370cdba78511b917e166f0b6dbecSteve Pfetsch        ptr[1] = 0x01;
1107635682da6daf370cdba78511b917e166f0b6dbecSteve Pfetsch        ptr[2] = 0x00;
1108635682da6daf370cdba78511b917e166f0b6dbecSteve Pfetsch        ptr[3] = 0x06;
1109635682da6daf370cdba78511b917e166f0b6dbecSteve Pfetsch        str2ba(bdaddr, (bdaddr_t *)(ptr + 4));
1110635682da6daf370cdba78511b917e166f0b6dbecSteve Pfetsch
1111635682da6daf370cdba78511b917e166f0b6dbecSteve Pfetsch        if (write(fd, cmd, WRITE_BDADDR_CMD_LEN) !=
1112635682da6daf370cdba78511b917e166f0b6dbecSteve Pfetsch                WRITE_BDADDR_CMD_LEN) {
1113635682da6daf370cdba78511b917e166f0b6dbecSteve Pfetsch            ALOGI("Failed to write BD_ADDR command\n");
1114635682da6daf370cdba78511b917e166f0b6dbecSteve Pfetsch            err = -ETIMEDOUT;
1115635682da6daf370cdba78511b917e166f0b6dbecSteve Pfetsch            goto failed;
1116635682da6daf370cdba78511b917e166f0b6dbecSteve Pfetsch        }
1117635682da6daf370cdba78511b917e166f0b6dbecSteve Pfetsch
1118635682da6daf370cdba78511b917e166f0b6dbecSteve Pfetsch        if (read_hci_event(fd, rsp, sizeof(rsp)) < 0) {
1119635682da6daf370cdba78511b917e166f0b6dbecSteve Pfetsch            ALOGI("Failed to set BD_ADDR\n");
1120635682da6daf370cdba78511b917e166f0b6dbecSteve Pfetsch            err = -ETIMEDOUT;
1121635682da6daf370cdba78511b917e166f0b6dbecSteve Pfetsch            goto failed;
1122635682da6daf370cdba78511b917e166f0b6dbecSteve Pfetsch        }
1123635682da6daf370cdba78511b917e166f0b6dbecSteve Pfetsch    }
1124635682da6daf370cdba78511b917e166f0b6dbecSteve Pfetsch
1125635682da6daf370cdba78511b917e166f0b6dbecSteve Pfetsch    /* Send HCI Reset */
1126635682da6daf370cdba78511b917e166f0b6dbecSteve Pfetsch    cmd[1] = 0x03;
1127635682da6daf370cdba78511b917e166f0b6dbecSteve Pfetsch    cmd[2] = 0x0C;
1128635682da6daf370cdba78511b917e166f0b6dbecSteve Pfetsch    cmd[3] = 0x00;
1129635682da6daf370cdba78511b917e166f0b6dbecSteve Pfetsch
1130635682da6daf370cdba78511b917e166f0b6dbecSteve Pfetsch    r = write(fd, cmd, 4);
1131635682da6daf370cdba78511b917e166f0b6dbecSteve Pfetsch    if (r != 4) {
1132635682da6daf370cdba78511b917e166f0b6dbecSteve Pfetsch        err = -ETIMEDOUT;
1133635682da6daf370cdba78511b917e166f0b6dbecSteve Pfetsch        goto failed;
1134635682da6daf370cdba78511b917e166f0b6dbecSteve Pfetsch    }
1135635682da6daf370cdba78511b917e166f0b6dbecSteve Pfetsch
1136635682da6daf370cdba78511b917e166f0b6dbecSteve Pfetsch    nanosleep(&tm, NULL);
1137635682da6daf370cdba78511b917e166f0b6dbecSteve Pfetsch    if (read_hci_event(fd, rsp, sizeof(rsp)) < 0) {
1138635682da6daf370cdba78511b917e166f0b6dbecSteve Pfetsch        err = -ETIMEDOUT;
1139635682da6daf370cdba78511b917e166f0b6dbecSteve Pfetsch        goto failed;
1140635682da6daf370cdba78511b917e166f0b6dbecSteve Pfetsch    }
1141635682da6daf370cdba78511b917e166f0b6dbecSteve Pfetsch
1142635682da6daf370cdba78511b917e166f0b6dbecSteve Pfetsch    ALOGI("HCI Reset is done\n");
1143635682da6daf370cdba78511b917e166f0b6dbecSteve Pfetsch    err = set_cntrlr_baud(fd, speed);
1144635682da6daf370cdba78511b917e166f0b6dbecSteve Pfetsch    if (err < 0)
1145635682da6daf370cdba78511b917e166f0b6dbecSteve Pfetsch        ALOGI("set_cntrlr_baud0:%d,%d\n", speed, err);
1146635682da6daf370cdba78511b917e166f0b6dbecSteve Pfetsch
1147635682da6daf370cdba78511b917e166f0b6dbecSteve Pfetschfailed:
1148635682da6daf370cdba78511b917e166f0b6dbecSteve Pfetsch    if (err < 0) {
1149635682da6daf370cdba78511b917e166f0b6dbecSteve Pfetsch        set_cntrlr_baud(fd, init_speed);
1150635682da6daf370cdba78511b917e166f0b6dbecSteve Pfetsch        set_speed(fd, ti, init_speed);
1151635682da6daf370cdba78511b917e166f0b6dbecSteve Pfetsch    }
1152635682da6daf370cdba78511b917e166f0b6dbecSteve Pfetsch
1153635682da6daf370cdba78511b917e166f0b6dbecSteve Pfetsch    return err;
1154635682da6daf370cdba78511b917e166f0b6dbecSteve Pfetsch
1155635682da6daf370cdba78511b917e166f0b6dbecSteve Pfetsch}
1156635682da6daf370cdba78511b917e166f0b6dbecSteve Pfetsch#define BTPROTO_HCI 1
1157635682da6daf370cdba78511b917e166f0b6dbecSteve Pfetsch
1158635682da6daf370cdba78511b917e166f0b6dbecSteve Pfetsch/* Open HCI device.
1159635682da6daf370cdba78511b917e166f0b6dbecSteve Pfetsch * Returns device descriptor (dd). */
1160635682da6daf370cdba78511b917e166f0b6dbecSteve Pfetschint hci_open_dev(int dev_id)
1161635682da6daf370cdba78511b917e166f0b6dbecSteve Pfetsch{
1162635682da6daf370cdba78511b917e166f0b6dbecSteve Pfetsch    struct sockaddr_hci a;
1163635682da6daf370cdba78511b917e166f0b6dbecSteve Pfetsch    int dd, err;
1164635682da6daf370cdba78511b917e166f0b6dbecSteve Pfetsch
1165635682da6daf370cdba78511b917e166f0b6dbecSteve Pfetsch    /* Create HCI socket */
1166635682da6daf370cdba78511b917e166f0b6dbecSteve Pfetsch    dd = socket(AF_BLUETOOTH, SOCK_RAW, BTPROTO_HCI);
1167635682da6daf370cdba78511b917e166f0b6dbecSteve Pfetsch    if (dd < 0)
1168635682da6daf370cdba78511b917e166f0b6dbecSteve Pfetsch        return dd;
1169635682da6daf370cdba78511b917e166f0b6dbecSteve Pfetsch
1170635682da6daf370cdba78511b917e166f0b6dbecSteve Pfetsch    /* Bind socket to the HCI device */
1171635682da6daf370cdba78511b917e166f0b6dbecSteve Pfetsch    memset(&a, 0, sizeof(a));
1172635682da6daf370cdba78511b917e166f0b6dbecSteve Pfetsch    a.hci_family = AF_BLUETOOTH;
1173635682da6daf370cdba78511b917e166f0b6dbecSteve Pfetsch    a.hci_dev = dev_id;
1174635682da6daf370cdba78511b917e166f0b6dbecSteve Pfetsch    if (bind(dd, (struct sockaddr *) &a, sizeof(a)) < 0)
1175635682da6daf370cdba78511b917e166f0b6dbecSteve Pfetsch        goto failed;
1176635682da6daf370cdba78511b917e166f0b6dbecSteve Pfetsch
1177635682da6daf370cdba78511b917e166f0b6dbecSteve Pfetsch    return dd;
1178635682da6daf370cdba78511b917e166f0b6dbecSteve Pfetsch
1179635682da6daf370cdba78511b917e166f0b6dbecSteve Pfetschfailed:
1180635682da6daf370cdba78511b917e166f0b6dbecSteve Pfetsch    err = errno;
1181635682da6daf370cdba78511b917e166f0b6dbecSteve Pfetsch    close(dd);
1182635682da6daf370cdba78511b917e166f0b6dbecSteve Pfetsch    errno = err;
1183635682da6daf370cdba78511b917e166f0b6dbecSteve Pfetsch
1184635682da6daf370cdba78511b917e166f0b6dbecSteve Pfetsch    return -1;
1185635682da6daf370cdba78511b917e166f0b6dbecSteve Pfetsch}
1186635682da6daf370cdba78511b917e166f0b6dbecSteve Pfetsch
1187635682da6daf370cdba78511b917e166f0b6dbecSteve Pfetschint hci_close_dev(int dd)
1188635682da6daf370cdba78511b917e166f0b6dbecSteve Pfetsch{
1189635682da6daf370cdba78511b917e166f0b6dbecSteve Pfetsch    return close(dd);
1190635682da6daf370cdba78511b917e166f0b6dbecSteve Pfetsch}
1191635682da6daf370cdba78511b917e166f0b6dbecSteve Pfetsch
1192635682da6daf370cdba78511b917e166f0b6dbecSteve Pfetsch/* HCI functions that require open device
1193635682da6daf370cdba78511b917e166f0b6dbecSteve Pfetsch * dd - Device descriptor returned by hci_open_dev. */
1194635682da6daf370cdba78511b917e166f0b6dbecSteve Pfetsch
1195635682da6daf370cdba78511b917e166f0b6dbecSteve Pfetschint hci_send_cmd(int dd, uint16_t ogf, uint16_t ocf, uint8_t plen, void *param)
1196635682da6daf370cdba78511b917e166f0b6dbecSteve Pfetsch{
1197635682da6daf370cdba78511b917e166f0b6dbecSteve Pfetsch    uint8_t type = HCI_COMMAND_PKT;
1198635682da6daf370cdba78511b917e166f0b6dbecSteve Pfetsch    hci_command_hdr hc;
1199635682da6daf370cdba78511b917e166f0b6dbecSteve Pfetsch    struct iovec iv[3];
1200635682da6daf370cdba78511b917e166f0b6dbecSteve Pfetsch    int ivn;
1201635682da6daf370cdba78511b917e166f0b6dbecSteve Pfetsch
1202635682da6daf370cdba78511b917e166f0b6dbecSteve Pfetsch    hc.opcode = htobs(cmd_opcode_pack(ogf, ocf));
1203635682da6daf370cdba78511b917e166f0b6dbecSteve Pfetsch    hc.plen= plen;
1204635682da6daf370cdba78511b917e166f0b6dbecSteve Pfetsch
1205635682da6daf370cdba78511b917e166f0b6dbecSteve Pfetsch    iv[0].iov_base = &type;
1206635682da6daf370cdba78511b917e166f0b6dbecSteve Pfetsch    iv[0].iov_len  = 1;
1207635682da6daf370cdba78511b917e166f0b6dbecSteve Pfetsch    iv[1].iov_base = &hc;
1208635682da6daf370cdba78511b917e166f0b6dbecSteve Pfetsch    iv[1].iov_len  = HCI_COMMAND_HDR_SIZE;
1209635682da6daf370cdba78511b917e166f0b6dbecSteve Pfetsch    ivn = 2;
1210635682da6daf370cdba78511b917e166f0b6dbecSteve Pfetsch
1211635682da6daf370cdba78511b917e166f0b6dbecSteve Pfetsch    if (plen) {
1212635682da6daf370cdba78511b917e166f0b6dbecSteve Pfetsch        iv[2].iov_base = param;
1213635682da6daf370cdba78511b917e166f0b6dbecSteve Pfetsch        iv[2].iov_len  = plen;
1214635682da6daf370cdba78511b917e166f0b6dbecSteve Pfetsch        ivn = 3;
1215635682da6daf370cdba78511b917e166f0b6dbecSteve Pfetsch    }
1216635682da6daf370cdba78511b917e166f0b6dbecSteve Pfetsch
1217635682da6daf370cdba78511b917e166f0b6dbecSteve Pfetsch    while (writev(dd, iv, ivn) < 0) {
1218635682da6daf370cdba78511b917e166f0b6dbecSteve Pfetsch        if (errno == EAGAIN || errno == EINTR)
1219635682da6daf370cdba78511b917e166f0b6dbecSteve Pfetsch            continue;
1220635682da6daf370cdba78511b917e166f0b6dbecSteve Pfetsch        return -1;
1221635682da6daf370cdba78511b917e166f0b6dbecSteve Pfetsch    }
1222635682da6daf370cdba78511b917e166f0b6dbecSteve Pfetsch    return 0;
1223635682da6daf370cdba78511b917e166f0b6dbecSteve Pfetsch}
1224635682da6daf370cdba78511b917e166f0b6dbecSteve Pfetsch
1225635682da6daf370cdba78511b917e166f0b6dbecSteve Pfetsch#define HCI_SLEEP_CMD_OCF     0x04
1226635682da6daf370cdba78511b917e166f0b6dbecSteve Pfetsch#define TIOCSETD 0x5423
1227635682da6daf370cdba78511b917e166f0b6dbecSteve Pfetsch#define HCIUARTSETFLAGS _IOW('U', 204, int)
1228635682da6daf370cdba78511b917e166f0b6dbecSteve Pfetsch#define HCIUARTSETPROTO _IOW('U', 200, int)
1229635682da6daf370cdba78511b917e166f0b6dbecSteve Pfetsch#define HCIUARTGETDEVICE _IOW('U', 202, int)
1230635682da6daf370cdba78511b917e166f0b6dbecSteve Pfetsch/*
1231635682da6daf370cdba78511b917e166f0b6dbecSteve Pfetsch * Atheros AR300x specific initialization post callback
1232635682da6daf370cdba78511b917e166f0b6dbecSteve Pfetsch */
1233635682da6daf370cdba78511b917e166f0b6dbecSteve Pfetschint ath3k_post(int fd, int pm)
1234635682da6daf370cdba78511b917e166f0b6dbecSteve Pfetsch{
1235635682da6daf370cdba78511b917e166f0b6dbecSteve Pfetsch    int dev_id, dd;
1236635682da6daf370cdba78511b917e166f0b6dbecSteve Pfetsch    struct timespec tm = { 0, 50000};
1237635682da6daf370cdba78511b917e166f0b6dbecSteve Pfetsch
1238635682da6daf370cdba78511b917e166f0b6dbecSteve Pfetsch    sleep(1);
1239635682da6daf370cdba78511b917e166f0b6dbecSteve Pfetsch
1240635682da6daf370cdba78511b917e166f0b6dbecSteve Pfetsch    dev_id = ioctl(fd, HCIUARTGETDEVICE, 0);
1241635682da6daf370cdba78511b917e166f0b6dbecSteve Pfetsch    if (dev_id < 0) {
1242635682da6daf370cdba78511b917e166f0b6dbecSteve Pfetsch        perror("cannot get device id");
1243635682da6daf370cdba78511b917e166f0b6dbecSteve Pfetsch        return dev_id;
1244635682da6daf370cdba78511b917e166f0b6dbecSteve Pfetsch    }
1245635682da6daf370cdba78511b917e166f0b6dbecSteve Pfetsch
1246635682da6daf370cdba78511b917e166f0b6dbecSteve Pfetsch    dd = hci_open_dev(dev_id);
1247635682da6daf370cdba78511b917e166f0b6dbecSteve Pfetsch    if (dd < 0) {
1248635682da6daf370cdba78511b917e166f0b6dbecSteve Pfetsch        perror("HCI device open failed");
1249635682da6daf370cdba78511b917e166f0b6dbecSteve Pfetsch        return dd;
1250635682da6daf370cdba78511b917e166f0b6dbecSteve Pfetsch    }
1251635682da6daf370cdba78511b917e166f0b6dbecSteve Pfetsch
1252635682da6daf370cdba78511b917e166f0b6dbecSteve Pfetsch    if (ioctl(dd, HCIDEVUP, dev_id) < 0 && errno != EALREADY) {
1253635682da6daf370cdba78511b917e166f0b6dbecSteve Pfetsch        perror("hci down:Power management Disabled");
1254635682da6daf370cdba78511b917e166f0b6dbecSteve Pfetsch        hci_close_dev(dd);
1255635682da6daf370cdba78511b917e166f0b6dbecSteve Pfetsch        return -1;
1256635682da6daf370cdba78511b917e166f0b6dbecSteve Pfetsch    }
1257635682da6daf370cdba78511b917e166f0b6dbecSteve Pfetsch
1258635682da6daf370cdba78511b917e166f0b6dbecSteve Pfetsch    /* send vendor specific command with Sleep feature Enabled */
1259635682da6daf370cdba78511b917e166f0b6dbecSteve Pfetsch    if (hci_send_cmd(dd, OGF_VENDOR_CMD, HCI_SLEEP_CMD_OCF, 1, &pm) < 0)
1260635682da6daf370cdba78511b917e166f0b6dbecSteve Pfetsch        perror("PM command failed, power management Disabled");
1261635682da6daf370cdba78511b917e166f0b6dbecSteve Pfetsch
1262635682da6daf370cdba78511b917e166f0b6dbecSteve Pfetsch    nanosleep(&tm, NULL);
1263635682da6daf370cdba78511b917e166f0b6dbecSteve Pfetsch    hci_close_dev(dd);
1264635682da6daf370cdba78511b917e166f0b6dbecSteve Pfetsch
1265635682da6daf370cdba78511b917e166f0b6dbecSteve Pfetsch    return 0;
1266635682da6daf370cdba78511b917e166f0b6dbecSteve Pfetsch}
1267635682da6daf370cdba78511b917e166f0b6dbecSteve Pfetsch
1268635682da6daf370cdba78511b917e166f0b6dbecSteve Pfetsch
1269635682da6daf370cdba78511b917e166f0b6dbecSteve Pfetsch
1270635682da6daf370cdba78511b917e166f0b6dbecSteve Pfetsch#define FLOW_CTL    0x0001
1271635682da6daf370cdba78511b917e166f0b6dbecSteve Pfetsch#define ENABLE_PM   1
1272635682da6daf370cdba78511b917e166f0b6dbecSteve Pfetsch#define DISABLE_PM  0
1273635682da6daf370cdba78511b917e166f0b6dbecSteve Pfetsch
1274635682da6daf370cdba78511b917e166f0b6dbecSteve Pfetsch/* Initialize UART driver */
1275635682da6daf370cdba78511b917e166f0b6dbecSteve Pfetschstatic int init_uart(char *dev, struct uart_t *u, int send_break, int raw)
1276635682da6daf370cdba78511b917e166f0b6dbecSteve Pfetsch{
1277635682da6daf370cdba78511b917e166f0b6dbecSteve Pfetsch    ALOGI(" %s ", __FUNCTION__);
1278635682da6daf370cdba78511b917e166f0b6dbecSteve Pfetsch
1279635682da6daf370cdba78511b917e166f0b6dbecSteve Pfetsch    struct termios ti;
1280635682da6daf370cdba78511b917e166f0b6dbecSteve Pfetsch
1281635682da6daf370cdba78511b917e166f0b6dbecSteve Pfetsch    int i, fd;
1282635682da6daf370cdba78511b917e166f0b6dbecSteve Pfetsch    unsigned long flags = 0;
1283635682da6daf370cdba78511b917e166f0b6dbecSteve Pfetsch
1284635682da6daf370cdba78511b917e166f0b6dbecSteve Pfetsch    if (raw)
1285635682da6daf370cdba78511b917e166f0b6dbecSteve Pfetsch        flags |= 1 << HCI_UART_RAW_DEVICE;
1286635682da6daf370cdba78511b917e166f0b6dbecSteve Pfetsch
1287635682da6daf370cdba78511b917e166f0b6dbecSteve Pfetsch
1288635682da6daf370cdba78511b917e166f0b6dbecSteve Pfetsch    fd = open(dev, O_RDWR | O_NOCTTY);
1289635682da6daf370cdba78511b917e166f0b6dbecSteve Pfetsch
1290635682da6daf370cdba78511b917e166f0b6dbecSteve Pfetsch    if (fd < 0) {
1291635682da6daf370cdba78511b917e166f0b6dbecSteve Pfetsch        ALOGI("Can't open serial port");
1292635682da6daf370cdba78511b917e166f0b6dbecSteve Pfetsch        return -1;
1293635682da6daf370cdba78511b917e166f0b6dbecSteve Pfetsch    }
1294635682da6daf370cdba78511b917e166f0b6dbecSteve Pfetsch
1295635682da6daf370cdba78511b917e166f0b6dbecSteve Pfetsch
1296635682da6daf370cdba78511b917e166f0b6dbecSteve Pfetsch    tcflush(fd, TCIOFLUSH);
1297635682da6daf370cdba78511b917e166f0b6dbecSteve Pfetsch
1298635682da6daf370cdba78511b917e166f0b6dbecSteve Pfetsch    if (tcgetattr(fd, &ti) < 0) {
1299635682da6daf370cdba78511b917e166f0b6dbecSteve Pfetsch        ALOGI("Can't get port settings: %d\n", errno);
1300635682da6daf370cdba78511b917e166f0b6dbecSteve Pfetsch        return -1;
1301635682da6daf370cdba78511b917e166f0b6dbecSteve Pfetsch    }
1302635682da6daf370cdba78511b917e166f0b6dbecSteve Pfetsch
1303635682da6daf370cdba78511b917e166f0b6dbecSteve Pfetsch    cfmakeraw(&ti);
1304635682da6daf370cdba78511b917e166f0b6dbecSteve Pfetsch
1305635682da6daf370cdba78511b917e166f0b6dbecSteve Pfetsch    ti.c_cflag |= CLOCAL;
1306635682da6daf370cdba78511b917e166f0b6dbecSteve Pfetsch    if (u->flags & FLOW_CTL)
1307635682da6daf370cdba78511b917e166f0b6dbecSteve Pfetsch        ti.c_cflag |= CRTSCTS;
1308635682da6daf370cdba78511b917e166f0b6dbecSteve Pfetsch    else
1309635682da6daf370cdba78511b917e166f0b6dbecSteve Pfetsch        ti.c_cflag &= ~CRTSCTS;
1310635682da6daf370cdba78511b917e166f0b6dbecSteve Pfetsch
1311635682da6daf370cdba78511b917e166f0b6dbecSteve Pfetsch    if (tcsetattr(fd, TCSANOW, &ti) < 0) {
1312635682da6daf370cdba78511b917e166f0b6dbecSteve Pfetsch        ALOGI("Can't set port settings");
1313635682da6daf370cdba78511b917e166f0b6dbecSteve Pfetsch        return -1;
1314635682da6daf370cdba78511b917e166f0b6dbecSteve Pfetsch    }
1315635682da6daf370cdba78511b917e166f0b6dbecSteve Pfetsch
1316635682da6daf370cdba78511b917e166f0b6dbecSteve Pfetsch    if (set_speed(fd, &ti, u->init_speed) < 0) {
1317635682da6daf370cdba78511b917e166f0b6dbecSteve Pfetsch        ALOGI("Can't set initial baud rate");
1318635682da6daf370cdba78511b917e166f0b6dbecSteve Pfetsch        return -1;
1319635682da6daf370cdba78511b917e166f0b6dbecSteve Pfetsch    }
1320635682da6daf370cdba78511b917e166f0b6dbecSteve Pfetsch
1321635682da6daf370cdba78511b917e166f0b6dbecSteve Pfetsch    tcflush(fd, TCIOFLUSH);
1322635682da6daf370cdba78511b917e166f0b6dbecSteve Pfetsch
1323635682da6daf370cdba78511b917e166f0b6dbecSteve Pfetsch    if (send_break) {
1324635682da6daf370cdba78511b917e166f0b6dbecSteve Pfetsch        tcsendbreak(fd, 0);
1325635682da6daf370cdba78511b917e166f0b6dbecSteve Pfetsch        usleep(500000);
1326635682da6daf370cdba78511b917e166f0b6dbecSteve Pfetsch    }
1327635682da6daf370cdba78511b917e166f0b6dbecSteve Pfetsch
1328635682da6daf370cdba78511b917e166f0b6dbecSteve Pfetsch    ath3k_init(fd,u->speed,u->init_speed,u->bdaddr, &ti);
1329635682da6daf370cdba78511b917e166f0b6dbecSteve Pfetsch
1330635682da6daf370cdba78511b917e166f0b6dbecSteve Pfetsch    ALOGI("Device setup complete\n");
1331635682da6daf370cdba78511b917e166f0b6dbecSteve Pfetsch
1332635682da6daf370cdba78511b917e166f0b6dbecSteve Pfetsch
1333635682da6daf370cdba78511b917e166f0b6dbecSteve Pfetsch    tcflush(fd, TCIOFLUSH);
1334635682da6daf370cdba78511b917e166f0b6dbecSteve Pfetsch
1335635682da6daf370cdba78511b917e166f0b6dbecSteve Pfetsch    // Set actual baudrate
1336635682da6daf370cdba78511b917e166f0b6dbecSteve Pfetsch    /*
1337635682da6daf370cdba78511b917e166f0b6dbecSteve Pfetsch    if (set_speed(fd, &ti, u->speed) < 0) {
1338635682da6daf370cdba78511b917e166f0b6dbecSteve Pfetsch        perror("Can't set baud rate");
1339635682da6daf370cdba78511b917e166f0b6dbecSteve Pfetsch        return -1;
1340635682da6daf370cdba78511b917e166f0b6dbecSteve Pfetsch    }
1341635682da6daf370cdba78511b917e166f0b6dbecSteve Pfetsch
1342635682da6daf370cdba78511b917e166f0b6dbecSteve Pfetsch    i = N_HCI;
1343635682da6daf370cdba78511b917e166f0b6dbecSteve Pfetsch    if (ioctl(fd, TIOCSETD, &i) < 0) {
1344635682da6daf370cdba78511b917e166f0b6dbecSteve Pfetsch        perror("Can't set line discipline");
1345635682da6daf370cdba78511b917e166f0b6dbecSteve Pfetsch        return -1;
1346635682da6daf370cdba78511b917e166f0b6dbecSteve Pfetsch    }
1347635682da6daf370cdba78511b917e166f0b6dbecSteve Pfetsch
1348635682da6daf370cdba78511b917e166f0b6dbecSteve Pfetsch    if (flags && ioctl(fd, HCIUARTSETFLAGS, flags) < 0) {
1349635682da6daf370cdba78511b917e166f0b6dbecSteve Pfetsch        perror("Can't set UART flags");
1350635682da6daf370cdba78511b917e166f0b6dbecSteve Pfetsch        return -1;
1351635682da6daf370cdba78511b917e166f0b6dbecSteve Pfetsch    }
1352635682da6daf370cdba78511b917e166f0b6dbecSteve Pfetsch
1353635682da6daf370cdba78511b917e166f0b6dbecSteve Pfetsch    if (ioctl(fd, HCIUARTSETPROTO, u->proto) < 0) {
1354635682da6daf370cdba78511b917e166f0b6dbecSteve Pfetsch        perror("Can't set device");
1355635682da6daf370cdba78511b917e166f0b6dbecSteve Pfetsch        return -1;
1356635682da6daf370cdba78511b917e166f0b6dbecSteve Pfetsch    }
1357635682da6daf370cdba78511b917e166f0b6dbecSteve Pfetsch
1358635682da6daf370cdba78511b917e166f0b6dbecSteve Pfetsch#if !defined(SW_BOARD_HAVE_BLUETOOTH_RTK)
1359635682da6daf370cdba78511b917e166f0b6dbecSteve Pfetsch    ath3k_post(fd, u->pm);
1360635682da6daf370cdba78511b917e166f0b6dbecSteve Pfetsch#endif
1361635682da6daf370cdba78511b917e166f0b6dbecSteve Pfetsch    */
1362635682da6daf370cdba78511b917e166f0b6dbecSteve Pfetsch
1363635682da6daf370cdba78511b917e166f0b6dbecSteve Pfetsch    return fd;
1364635682da6daf370cdba78511b917e166f0b6dbecSteve Pfetsch}
1365635682da6daf370cdba78511b917e166f0b6dbecSteve Pfetsch
1366635682da6daf370cdba78511b917e166f0b6dbecSteve Pfetsch
1367635682da6daf370cdba78511b917e166f0b6dbecSteve Pfetschint hw_config_ath3k(char *port_name)
1368635682da6daf370cdba78511b917e166f0b6dbecSteve Pfetsch{
1369635682da6daf370cdba78511b917e166f0b6dbecSteve Pfetsch    ALOGI(" %s ", __FUNCTION__);
1370635682da6daf370cdba78511b917e166f0b6dbecSteve Pfetsch    PSCounter=0;
1371635682da6daf370cdba78511b917e166f0b6dbecSteve Pfetsch    struct sigaction sa;
1372635682da6daf370cdba78511b917e166f0b6dbecSteve Pfetsch    struct uart_t u ;
1373635682da6daf370cdba78511b917e166f0b6dbecSteve Pfetsch    int n=0,send_break=0,raw=0;
1374635682da6daf370cdba78511b917e166f0b6dbecSteve Pfetsch
1375635682da6daf370cdba78511b917e166f0b6dbecSteve Pfetsch    memset(&u, 0, sizeof(u));
1376635682da6daf370cdba78511b917e166f0b6dbecSteve Pfetsch    u.speed =3000000;
1377635682da6daf370cdba78511b917e166f0b6dbecSteve Pfetsch    u.init_speed =115200;
1378635682da6daf370cdba78511b917e166f0b6dbecSteve Pfetsch    u.flags |= FLOW_CTL;
1379635682da6daf370cdba78511b917e166f0b6dbecSteve Pfetsch    u.pm = DISABLE_PM;
1380635682da6daf370cdba78511b917e166f0b6dbecSteve Pfetsch
1381635682da6daf370cdba78511b917e166f0b6dbecSteve Pfetsch    n = init_uart(port_name, &u, send_break, raw);
1382635682da6daf370cdba78511b917e166f0b6dbecSteve Pfetsch    if (n < 0) {
1383635682da6daf370cdba78511b917e166f0b6dbecSteve Pfetsch        ALOGI("Can't initialize device");
1384635682da6daf370cdba78511b917e166f0b6dbecSteve Pfetsch    }
1385635682da6daf370cdba78511b917e166f0b6dbecSteve Pfetsch
1386635682da6daf370cdba78511b917e166f0b6dbecSteve Pfetsch    return n;
1387635682da6daf370cdba78511b917e166f0b6dbecSteve Pfetsch}
1388635682da6daf370cdba78511b917e166f0b6dbecSteve Pfetsch
1389635682da6daf370cdba78511b917e166f0b6dbecSteve Pfetschvoid lpm_set_ar3k(uint8_t pio, uint8_t action, uint8_t polarity)
1390635682da6daf370cdba78511b917e166f0b6dbecSteve Pfetsch{
1391635682da6daf370cdba78511b917e166f0b6dbecSteve Pfetsch    int rc;
1392635682da6daf370cdba78511b917e166f0b6dbecSteve Pfetsch    int fd = -1;
1393635682da6daf370cdba78511b917e166f0b6dbecSteve Pfetsch    char buffer;
1394635682da6daf370cdba78511b917e166f0b6dbecSteve Pfetsch
1395635682da6daf370cdba78511b917e166f0b6dbecSteve Pfetsch    ALOGI("lpm mode: %d  action: %d", pio, action);
1396635682da6daf370cdba78511b917e166f0b6dbecSteve Pfetsch
1397635682da6daf370cdba78511b917e166f0b6dbecSteve Pfetsch    RESERVED(polarity);
1398635682da6daf370cdba78511b917e166f0b6dbecSteve Pfetsch
1399635682da6daf370cdba78511b917e166f0b6dbecSteve Pfetsch    switch (pio)
1400635682da6daf370cdba78511b917e166f0b6dbecSteve Pfetsch    {
1401635682da6daf370cdba78511b917e166f0b6dbecSteve Pfetsch        case UPIO_LPM_MODE:
1402635682da6daf370cdba78511b917e166f0b6dbecSteve Pfetsch            if (upio_state[UPIO_LPM_MODE] == action)
1403635682da6daf370cdba78511b917e166f0b6dbecSteve Pfetsch            {
1404635682da6daf370cdba78511b917e166f0b6dbecSteve Pfetsch                ALOGI("LPM is %s already", lpm_mode[action]);
1405635682da6daf370cdba78511b917e166f0b6dbecSteve Pfetsch                return;
1406635682da6daf370cdba78511b917e166f0b6dbecSteve Pfetsch            }
1407635682da6daf370cdba78511b917e166f0b6dbecSteve Pfetsch
1408635682da6daf370cdba78511b917e166f0b6dbecSteve Pfetsch            fd = open(VENDOR_LPM_PROC_NODE, O_WRONLY);
1409635682da6daf370cdba78511b917e166f0b6dbecSteve Pfetsch
1410635682da6daf370cdba78511b917e166f0b6dbecSteve Pfetsch            if (fd < 0)
1411635682da6daf370cdba78511b917e166f0b6dbecSteve Pfetsch            {
1412635682da6daf370cdba78511b917e166f0b6dbecSteve Pfetsch                ALOGE("upio_set : open(%s) for write failed: %s (%d)",
1413635682da6daf370cdba78511b917e166f0b6dbecSteve Pfetsch                VENDOR_LPM_PROC_NODE, strerror(errno), errno);
1414635682da6daf370cdba78511b917e166f0b6dbecSteve Pfetsch                return;
1415635682da6daf370cdba78511b917e166f0b6dbecSteve Pfetsch            }
1416635682da6daf370cdba78511b917e166f0b6dbecSteve Pfetsch
1417635682da6daf370cdba78511b917e166f0b6dbecSteve Pfetsch            if (action == UPIO_ASSERT)
1418635682da6daf370cdba78511b917e166f0b6dbecSteve Pfetsch            {
1419635682da6daf370cdba78511b917e166f0b6dbecSteve Pfetsch                buffer = '1';
1420635682da6daf370cdba78511b917e166f0b6dbecSteve Pfetsch            }
1421635682da6daf370cdba78511b917e166f0b6dbecSteve Pfetsch            else
1422635682da6daf370cdba78511b917e166f0b6dbecSteve Pfetsch            {
1423635682da6daf370cdba78511b917e166f0b6dbecSteve Pfetsch                buffer = '0';
1424635682da6daf370cdba78511b917e166f0b6dbecSteve Pfetsch            }
1425635682da6daf370cdba78511b917e166f0b6dbecSteve Pfetsch
1426635682da6daf370cdba78511b917e166f0b6dbecSteve Pfetsch            if (write(fd, &buffer, 1) < 0)
1427635682da6daf370cdba78511b917e166f0b6dbecSteve Pfetsch            {
1428635682da6daf370cdba78511b917e166f0b6dbecSteve Pfetsch                ALOGE("upio_set : write(%s) failed: %s (%d)",
1429635682da6daf370cdba78511b917e166f0b6dbecSteve Pfetsch                VENDOR_LPM_PROC_NODE, strerror(errno),errno);
1430635682da6daf370cdba78511b917e166f0b6dbecSteve Pfetsch            }
1431635682da6daf370cdba78511b917e166f0b6dbecSteve Pfetsch            else
1432635682da6daf370cdba78511b917e166f0b6dbecSteve Pfetsch            {
1433635682da6daf370cdba78511b917e166f0b6dbecSteve Pfetsch                upio_state[UPIO_LPM_MODE] = action;
1434635682da6daf370cdba78511b917e166f0b6dbecSteve Pfetsch                ALOGI("LPM is set to %s", lpm_mode[action]);
1435635682da6daf370cdba78511b917e166f0b6dbecSteve Pfetsch            }
1436635682da6daf370cdba78511b917e166f0b6dbecSteve Pfetsch
1437635682da6daf370cdba78511b917e166f0b6dbecSteve Pfetsch            if (fd >= 0)
1438635682da6daf370cdba78511b917e166f0b6dbecSteve Pfetsch                close(fd);
1439635682da6daf370cdba78511b917e166f0b6dbecSteve Pfetsch
1440635682da6daf370cdba78511b917e166f0b6dbecSteve Pfetsch            break;
1441635682da6daf370cdba78511b917e166f0b6dbecSteve Pfetsch
1442635682da6daf370cdba78511b917e166f0b6dbecSteve Pfetsch        case UPIO_BT_WAKE:
1443635682da6daf370cdba78511b917e166f0b6dbecSteve Pfetsch            /* UPIO_DEASSERT should be allowed because in Rx case assert occur
1444635682da6daf370cdba78511b917e166f0b6dbecSteve Pfetsch            * from the remote side where as deassert  will be initiated from Host
1445635682da6daf370cdba78511b917e166f0b6dbecSteve Pfetsch            */
1446635682da6daf370cdba78511b917e166f0b6dbecSteve Pfetsch            if ((action == UPIO_ASSERT) && (upio_state[UPIO_BT_WAKE] == action))
1447635682da6daf370cdba78511b917e166f0b6dbecSteve Pfetsch            {
1448635682da6daf370cdba78511b917e166f0b6dbecSteve Pfetsch                ALOGI("BT_WAKE is %s already", lpm_state[action]);
1449635682da6daf370cdba78511b917e166f0b6dbecSteve Pfetsch
1450635682da6daf370cdba78511b917e166f0b6dbecSteve Pfetsch                return;
1451635682da6daf370cdba78511b917e166f0b6dbecSteve Pfetsch            }
1452635682da6daf370cdba78511b917e166f0b6dbecSteve Pfetsch
1453635682da6daf370cdba78511b917e166f0b6dbecSteve Pfetsch            if (action == UPIO_DEASSERT)
1454635682da6daf370cdba78511b917e166f0b6dbecSteve Pfetsch                buffer = '0';
1455635682da6daf370cdba78511b917e166f0b6dbecSteve Pfetsch            else
1456635682da6daf370cdba78511b917e166f0b6dbecSteve Pfetsch                buffer = '1';
1457635682da6daf370cdba78511b917e166f0b6dbecSteve Pfetsch
1458635682da6daf370cdba78511b917e166f0b6dbecSteve Pfetsch            fd = open(VENDOR_BTWRITE_PROC_NODE, O_WRONLY);
1459635682da6daf370cdba78511b917e166f0b6dbecSteve Pfetsch
1460635682da6daf370cdba78511b917e166f0b6dbecSteve Pfetsch            if (fd < 0)
1461635682da6daf370cdba78511b917e166f0b6dbecSteve Pfetsch            {
1462635682da6daf370cdba78511b917e166f0b6dbecSteve Pfetsch                ALOGE("upio_set : open(%s) for write failed: %s (%d)",
1463635682da6daf370cdba78511b917e166f0b6dbecSteve Pfetsch                VENDOR_BTWRITE_PROC_NODE, strerror(errno), errno);
1464635682da6daf370cdba78511b917e166f0b6dbecSteve Pfetsch                return;
1465635682da6daf370cdba78511b917e166f0b6dbecSteve Pfetsch            }
1466635682da6daf370cdba78511b917e166f0b6dbecSteve Pfetsch
1467635682da6daf370cdba78511b917e166f0b6dbecSteve Pfetsch            if (write(fd, &buffer, 1) < 0)
1468635682da6daf370cdba78511b917e166f0b6dbecSteve Pfetsch            {
1469635682da6daf370cdba78511b917e166f0b6dbecSteve Pfetsch                ALOGE("upio_set : write(%s) failed: %s (%d)",
1470635682da6daf370cdba78511b917e166f0b6dbecSteve Pfetsch                VENDOR_BTWRITE_PROC_NODE, strerror(errno),errno);
1471635682da6daf370cdba78511b917e166f0b6dbecSteve Pfetsch            }
1472635682da6daf370cdba78511b917e166f0b6dbecSteve Pfetsch            else
1473635682da6daf370cdba78511b917e166f0b6dbecSteve Pfetsch            {
1474635682da6daf370cdba78511b917e166f0b6dbecSteve Pfetsch                upio_state[UPIO_BT_WAKE] = action;
1475635682da6daf370cdba78511b917e166f0b6dbecSteve Pfetsch                ALOGI("BT_WAKE is set to %s", lpm_state[action]);
1476635682da6daf370cdba78511b917e166f0b6dbecSteve Pfetsch            }
1477635682da6daf370cdba78511b917e166f0b6dbecSteve Pfetsch
1478635682da6daf370cdba78511b917e166f0b6dbecSteve Pfetsch            ALOGI("proc btwrite assertion");
1479635682da6daf370cdba78511b917e166f0b6dbecSteve Pfetsch
1480635682da6daf370cdba78511b917e166f0b6dbecSteve Pfetsch            if (fd >= 0)
1481635682da6daf370cdba78511b917e166f0b6dbecSteve Pfetsch                close(fd);
1482635682da6daf370cdba78511b917e166f0b6dbecSteve Pfetsch
1483635682da6daf370cdba78511b917e166f0b6dbecSteve Pfetsch            break;
1484635682da6daf370cdba78511b917e166f0b6dbecSteve Pfetsch
1485635682da6daf370cdba78511b917e166f0b6dbecSteve Pfetsch        case UPIO_HOST_WAKE:
1486635682da6daf370cdba78511b917e166f0b6dbecSteve Pfetsch            ALOGI("upio_set: UPIO_HOST_WAKE");
1487635682da6daf370cdba78511b917e166f0b6dbecSteve Pfetsch            break;
1488635682da6daf370cdba78511b917e166f0b6dbecSteve Pfetsch    }
1489635682da6daf370cdba78511b917e166f0b6dbecSteve Pfetsch
1490635682da6daf370cdba78511b917e166f0b6dbecSteve Pfetsch}
1491