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