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