blob: c3e9fdeb8340ab9f135c08fd0f50c5285dee4e31 [file] [log] [blame]
/*
*
* Copyright (c) 2013-2015, The Linux Foundation. All rights reserved.
* Not a Contribution.
*
* Copyright 2012 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License"); you
* may not use this file except in compliance with the License. You may
* obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
* implied. See the License for the specific language governing
* permissions and limitations under the License.
*
*/
/******************************************************************************
*
* Filename: hciattach_rome.c
*
* Description: Contains controller-specific functions, like
* firmware patch download
* low power mode operations
*
******************************************************************************/
#define LOG_TAG "bt_vendor"
#include <stdio.h>
#include <unistd.h>
#include <sys/socket.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <sys/ioctl.h>
#include <signal.h>
#include <time.h>
#include <errno.h>
#include <fcntl.h>
#include <dirent.h>
#include <ctype.h>
#include <stdlib.h>
#include <string.h>
#include <termios.h>
#include <bluetooth/bluetooth.h>
#include "hciattach_rome.h"
#include "hciattach.h"
#ifdef __cplusplus
}
#endif
/******************************************************************************
** Variables
******************************************************************************/
FILE *file;
unsigned char *phdr_buffer;
unsigned char *pdata_buffer = NULL;
patch_info rampatch_patch_info;
int rome_ver = ROME_VER_UNKNOWN;
unsigned char gTlv_type;
unsigned char gtlv_dwndcfg;
char *rampatch_file_path;
char *nvm_file_path;
vnd_userial_cb_t vnd_userial;
unsigned char wait_vsc_evt = TRUE;
/******************************************************************************
** Extern variables
******************************************************************************/
//extern unsigned char vnd_local_bd_addr[6];
/*****************************************************************************
** Functions
*****************************************************************************/
/*******************************************************************************
**
** Function userial_to_tcio_baud
**
** Description helper function converts USERIAL baud rates into TCIO
** conforming baud rates
**
** Returns TRUE/FALSE
**
*******************************************************************************/
unsigned char userial_to_tcio_baud(unsigned char cfg_baud, unsigned int *baud)
{
if (cfg_baud == USERIAL_BAUD_115200)
*baud = B115200;
else if (cfg_baud == USERIAL_BAUD_4M)
*baud = B4000000;
else if (cfg_baud == USERIAL_BAUD_3M)
*baud = B3000000;
else if (cfg_baud == USERIAL_BAUD_2M)
*baud = B2000000;
else if (cfg_baud == USERIAL_BAUD_1M)
*baud = B1000000;
else if (cfg_baud == USERIAL_BAUD_921600)
*baud = B921600;
else if (cfg_baud == USERIAL_BAUD_460800)
*baud = B460800;
else if (cfg_baud == USERIAL_BAUD_230400)
*baud = B230400;
else if (cfg_baud == USERIAL_BAUD_57600)
*baud = B57600;
else if (cfg_baud == USERIAL_BAUD_19200)
*baud = B19200;
else if (cfg_baud == USERIAL_BAUD_9600)
*baud = B9600;
else if (cfg_baud == USERIAL_BAUD_1200)
*baud = B1200;
else if (cfg_baud == USERIAL_BAUD_600)
*baud = B600;
else
{
fprintf(stderr, "userial vendor open: unsupported baud idx %i\n", cfg_baud);
*baud = B115200;
return FALSE;
}
return TRUE;
}
/*******************************************************************************
**
** Function userial_vendor_set_baud
**
** Description Set new baud rate
**
** Returns None
**
*******************************************************************************/
void userial_vendor_set_baud(unsigned char userial_baud)
{
unsigned int tcio_baud;
fprintf(stderr, "## userial_vendor_set_baud: %d\n", userial_baud);
if (tcgetattr(vnd_userial.fd, &vnd_userial.termios) < 0) {
perror("Can't get port settings");
return;
}
cfmakeraw(&vnd_userial.termios);
vnd_userial.termios.c_cflag |= CLOCAL;
vnd_userial.termios.c_cflag |= CREAD;
vnd_userial.termios.c_cflag |= CS8;
tcsetattr(vnd_userial.fd, TCSANOW, &vnd_userial.termios);
userial_to_tcio_baud(userial_baud, &tcio_baud);
cfsetospeed(&vnd_userial.termios, tcio_baud);
cfsetispeed(&vnd_userial.termios, tcio_baud);
tcsetattr(vnd_userial.fd, TCSADRAIN, &vnd_userial.termios); /* don't change speed until last write done */
}
/*******************************************************************************
**
** Function userial_vendor_ioctl
**
** Description ioctl inteface
**
** Returns None
**
*******************************************************************************/
int userial_vendor_ioctl(int fd, userial_vendor_ioctl_op_t op, int *p_data)
{
int err = -1;
struct termios ti;
if (tcgetattr(fd, &ti) < 0) {
perror("Can't get port settings");
return -1;
}
cfmakeraw(&ti);
ti.c_cflag |= CLOCAL;
ti.c_cflag |= CREAD;
ti.c_cflag |= CS8;
switch(op)
{
#if (BT_WAKE_VIA_USERIAL_IOCTL==TRUE)
case USERIAL_OP_ASSERT_BT_WAKE:
VNDUSERIALDBG("## userial_vendor_ioctl: Asserting BT_Wake ##");
err = ioctl(fd, USERIAL_IOCTL_BT_WAKE_ASSERT, NULL);
break;
case USERIAL_OP_DEASSERT_BT_WAKE:
VNDUSERIALDBG("## userial_vendor_ioctl: De-asserting BT_Wake ##");
err = ioctl(fd, USERIAL_IOCTL_BT_WAKE_DEASSERT, NULL);
break;
case USERIAL_OP_GET_BT_WAKE_STATE:
err = ioctl(fd, USERIAL_IOCTL_BT_WAKE_GET_ST, p_data);
break;
#endif // (BT_WAKE_VIA_USERIAL_IOCTL==TRUE)
case USERIAL_OP_FLOW_ON:
fprintf(stderr, "## userial_vendor_ioctl: UART Flow On\n ");
ti.c_cflag |= CRTSCTS;
if (err = tcsetattr(fd, TCSANOW, &ti) < 0) {
perror("Can't set port settings");
return -1;
}
break;
case USERIAL_OP_FLOW_OFF:
fprintf(stderr, "## userial_vendor_ioctl: UART Flow Off\n ");
ti.c_cflag &= ~CRTSCTS;
if (err = tcsetattr(fd, TCSANOW, &ti) < 0) {
fprintf(stderr, "Can't set port settings");
return -1;
}
break;
default:
break;
}
return err;
}
int get_vs_hci_event(unsigned char *rsp)
{
int err = 0, soc_id =0;
unsigned char paramlen = 0;
if( (rsp[EVENTCODE_OFFSET] == VSEVENT_CODE) || (rsp[EVENTCODE_OFFSET] == EVT_CMD_COMPLETE))
fprintf(stderr, "%s: Received HCI-Vendor Specific event\n", __FUNCTION__);
else {
fprintf(stderr, "%s: Failed to receive HCI-Vendor Specific event\n", __FUNCTION__);
err = -EIO;
goto failed;
}
fprintf(stderr, "%s: Parameter Length: 0x%x\n", __FUNCTION__, paramlen = rsp[EVT_PLEN]);
fprintf(stderr, "%s: Command response: 0x%x\n", __FUNCTION__, rsp[CMD_RSP_OFFSET]);
fprintf(stderr, "%s: Response type : 0x%x\n", __FUNCTION__, rsp[RSP_TYPE_OFFSET]);
/* Check the status of the operation */
switch ( rsp[CMD_RSP_OFFSET] )
{
case EDL_CMD_REQ_RES_EVT:
fprintf(stderr, "%s: Command Request Response\n", __FUNCTION__);
switch(rsp[RSP_TYPE_OFFSET])
{
case EDL_PATCH_VER_RES_EVT:
case EDL_APP_VER_RES_EVT:
fprintf(stderr, "\t Current Product ID\t\t: 0x%08x\n",
(unsigned int)(rsp[PATCH_PROD_ID_OFFSET +3] << 24 |
rsp[PATCH_PROD_ID_OFFSET+2] << 16 |
rsp[PATCH_PROD_ID_OFFSET+1] << 8 |
rsp[PATCH_PROD_ID_OFFSET] ));
/* Patch Version indicates FW patch version */
fprintf(stderr, "\t Current Patch Version\t\t: 0x%04x\n",
(unsigned short)(rsp[PATCH_PATCH_VER_OFFSET + 1] << 8 |
rsp[PATCH_PATCH_VER_OFFSET] ));
/* ROM Build Version indicates ROM build version like 1.0/1.1/2.0 */
fprintf(stderr, "\t Current ROM Build Version\t: 0x%04x\n", rome_ver =
(int)(rsp[PATCH_ROM_BUILD_VER_OFFSET + 1] << 8 |
rsp[PATCH_ROM_BUILD_VER_OFFSET] ));
/* In case rome 1.0/1.1, there is no SOC ID version available */
if (paramlen - 10)
{
fprintf(stderr, "\t Current SOC Version\t\t: 0x%08x\n", soc_id =
(unsigned int)(rsp[PATCH_SOC_VER_OFFSET +3] << 24 |
rsp[PATCH_SOC_VER_OFFSET+2] << 16 |
rsp[PATCH_SOC_VER_OFFSET+1] << 8 |
rsp[PATCH_SOC_VER_OFFSET] ));
}
/* Rome Chipset Version can be decided by Patch version and SOC version,
Upper 2 bytes will be used for Patch version and Lower 2 bytes will be
used for SOC as combination for BT host driver */
rome_ver = (rome_ver << 16) | (soc_id & 0x0000ffff);
break;
case EDL_TVL_DNLD_RES_EVT:
case EDL_CMD_EXE_STATUS_EVT:
switch (err = rsp[CMD_STATUS_OFFSET])
{
case HCI_CMD_SUCCESS:
fprintf(stderr, "%s: Download Packet successfully!\n", __FUNCTION__);
break;
case PATCH_LEN_ERROR:
fprintf(stderr, "%s: Invalid patch length argument passed for EDL PATCH "
"SET REQ cmd\n", __FUNCTION__);
break;
case PATCH_VER_ERROR:
fprintf(stderr, "%s: Invalid patch version argument passed for EDL PATCH "
"SET REQ cmd\n", __FUNCTION__);
break;
case PATCH_CRC_ERROR:
fprintf(stderr, "%s: CRC check of patch failed!!!\n", __FUNCTION__);
break;
case PATCH_NOT_FOUND:
fprintf(stderr, "%s: Invalid patch data!!!\n", __FUNCTION__);
break;
case TLV_TYPE_ERROR:
fprintf(stderr, "%s: TLV Type Error !!!\n", __FUNCTION__);
break;
default:
fprintf(stderr, "%s: Undefined error (0x%x)", __FUNCTION__, err);
break;
}
break;
}
break;
case NVM_ACCESS_CODE:
fprintf(stderr, "%s: NVM Access Code!!!\n", __FUNCTION__);
err = HCI_CMD_SUCCESS;
break;
case EDL_SET_BAUDRATE_RSP_EVT:
/* Rome 1.1 has bug with the response, so it should ignore it. */
if (rsp[BAUDRATE_RSP_STATUS_OFFSET] != BAUDRATE_CHANGE_SUCCESS)
{
fprintf(stderr, "%s: Set Baudrate request failed - 0x%x\n", __FUNCTION__,
rsp[CMD_STATUS_OFFSET]);
err = -1;
}
break;
default:
fprintf(stderr, "%s: Not a valid status!!!\n", __FUNCTION__);
err = -1;
break;
}
failed:
return err;
}
int wait_for_data(int fd, int maxTimeOut)
{
fd_set infids;
struct timeval timeout;
if (maxTimeOut <= 0) {
fprintf(stderr, "%s: Invalid timeout value specified", __func__);
return -EINVAL;
}
FD_ZERO (&infids);
FD_SET (fd, &infids);
timeout.tv_sec = maxTimeOut;
timeout.tv_usec = 0;
/* Check whether data is available in TTY buffer before calling read() */
if (select (fd + 1, &infids, NULL, NULL, &timeout) < 1) {
fprintf(stderr, "%s: Timing out on select for %d secs.\n", __FUNCTION__, maxTimeOut);
return -1;
}
else
fprintf(stderr, "%s: HCI-VS-EVENT available in TTY Serial buffer\n",
__FUNCTION__);
return 1;
}
/*
* Read an VS HCI event from the given file descriptor.
*/
int read_vs_hci_event(int fd, unsigned char* buf, int size)
{
int remain, r, retry = 0;
int count = 0;
if (size <= 0) {
fprintf(stderr, "Invalid size arguement!\n");
return -1;
}
fprintf(stderr, "%s: Wait for HCI-Vendor Specfic Event from SOC\n",
__FUNCTION__);
/* Check whether data is available in TTY buffer before calling read() */
if (wait_for_data(fd, SELECT_TIMEOUT) < 1)
return -1;
/* The first byte identifies the packet type. For HCI event packets, it
* should be 0x04, so we read until we get to the 0x04. */
/* It will keep reading until find 0x04 byte */
while (1) {
/* Read UART Buffer for HCI-DATA */
r = read(fd, buf, 1);
if (r <= 0) {
fprintf(stderr, "%s: read() failed. error: %d\n",
__FUNCTION__, r);
return -1;
}
/* Check if received data is HCI-DATA or not.
* If not HCI-DATA, then retry reading the UART Buffer once.
* Sometimes there could be corruption on the UART lines and to
* avoid that retry once reading the UART Buffer for HCI-DATA.
*/
if (buf[0] == 0x04) { /* Recvd. HCI DATA */
retry = 0;
break;
}
else if (retry < MAX_RETRY_CNT){ /* Retry mechanism */
retry++;
fprintf(stderr, "%s: Not an HCI-VS-Event! buf[0]: %d",
__FUNCTION__, buf[0]);
if (wait_for_data(fd, SELECT_TIMEOUT) < 1)
return -1;
else /* Data available in UART Buffer: Continue to read */
continue;
}
else { /* RETRY failed : Exiting with failure */
fprintf(stderr, "%s: RETRY failed!", __FUNCTION__);
return -1;
}
}
count++;
fprintf(stderr, "%s: Wait for HCI-Vendor Specfic Event from SOC, buf[0] - 0x%x\n", __FUNCTION__, buf[0]);
/* The next two bytes are the event code and parameter total length. */
while (count < 3) {
r = read(fd, buf + count, 3 - count);
if ((r <= 0) || (buf[1] != 0xFF )) {
fprintf(stderr, "It is not VS event !!\n");
return -1;
}
count += r;
}
fprintf(stderr, "%s: Wait for HCI-Vendor Specfic Event from SOC, buf[1] - 0x%x\n", __FUNCTION__, buf[1]);
/* Now we read the parameters. */
if (buf[2] < (size - 3))
remain = buf[2];
else
remain = size - 3;
while ((count - 3) < remain) {
r = read(fd, buf + count, remain - (count - 3));
if (r <= 0)
return -1;
count += r;
}
/* Check if the set patch command is successful or not */
if(get_vs_hci_event(buf) != HCI_CMD_SUCCESS)
return -1;
fprintf(stderr, "%s: Wait for HCI-Vendor Specfic Event from SOC, count - 0x%x\n", __FUNCTION__, count);
return count;
}
int hci_send_vs_cmd(int fd, unsigned char *cmd, unsigned char *rsp, int size)
{
int ret = 0;
/* Send the HCI command packet to UART for transmission */
ret = write(fd, cmd, size);
if (ret != size) {
fprintf(stderr, "%s: Send failed with ret value: %d\n", __FUNCTION__, ret);
goto failed;
}
if (wait_vsc_evt) {
/* Check for response from the Controller */
if (read_vs_hci_event(fd, rsp, HCI_MAX_EVENT_SIZE) < 0) {
ret = -ETIMEDOUT;
fprintf(stderr, "%s: Failed to get HCI-VS Event from SOC\n", __FUNCTION__);
goto failed;
}
fprintf(stderr, "%s: Received HCI-Vendor Specific Event from SOC\n", __FUNCTION__);
}
failed:
return ret;
}
void frame_hci_cmd_pkt(
unsigned char *cmd,
int edl_cmd, unsigned int p_base_addr,
int segtNo, int size
)
{
int offset = 0;
hci_command_hdr *cmd_hdr;
memset(cmd, 0x0, HCI_MAX_CMD_SIZE);
cmd_hdr = (void *) (cmd + 1);
cmd[0] = HCI_COMMAND_PKT;
cmd_hdr->opcode = cmd_opcode_pack(HCI_VENDOR_CMD_OGF, HCI_PATCH_CMD_OCF);
cmd_hdr->plen = size;
cmd[4] = edl_cmd;
switch (edl_cmd)
{
case EDL_PATCH_SET_REQ_CMD:
/* Copy the patch header info as CMD params */
memcpy(&cmd[5], phdr_buffer, PATCH_HDR_LEN);
fprintf(stderr, "%s: Sending EDL_PATCH_SET_REQ_CMD\n", __FUNCTION__);
fprintf(stderr, "HCI-CMD %d:\t0x%x \t0x%x \t0x%x \t0x%x \t0x%x\n",
segtNo, cmd[0], cmd[1], cmd[2], cmd[3], cmd[4]);
break;
case EDL_PATCH_DLD_REQ_CMD:
offset = ((segtNo - 1) * MAX_DATA_PER_SEGMENT);
p_base_addr += offset;
cmd_hdr->plen = (size + 6);
cmd[5] = (size + 4);
cmd[6] = EXTRACT_BYTE(p_base_addr, 0);
cmd[7] = EXTRACT_BYTE(p_base_addr, 1);
cmd[8] = EXTRACT_BYTE(p_base_addr, 2);
cmd[9] = EXTRACT_BYTE(p_base_addr, 3);
memcpy(&cmd[10], (pdata_buffer + offset), size);
fprintf(stderr, "%s: Sending EDL_PATCH_DLD_REQ_CMD: size: %d bytes\n",
__FUNCTION__, size);
fprintf(stderr, "HCI-CMD %d:\t0x%x\t0x%x\t0x%x\t0x%x\t0x%x\t0x%x\t0x%x\t"
"0x%x\t0x%x\t0x%x\t\n", segtNo, cmd[0], cmd[1], cmd[2],
cmd[3], cmd[4], cmd[5], cmd[6], cmd[7], cmd[8], cmd[9]);
break;
case EDL_PATCH_ATCH_REQ_CMD:
fprintf(stderr, "%s: Sending EDL_PATCH_ATTACH_REQ_CMD\n", __FUNCTION__);
fprintf(stderr, "HCI-CMD %d:\t0x%x \t0x%x \t0x%x \t0x%x \t0x%x\n",
segtNo, cmd[0], cmd[1], cmd[2], cmd[3], cmd[4]);
break;
case EDL_PATCH_RST_REQ_CMD:
fprintf(stderr, "%s: Sending EDL_PATCH_RESET_REQ_CMD\n", __FUNCTION__);
fprintf(stderr, "HCI-CMD %d:\t0x%x \t0x%x \t0x%x \t0x%x \t0x%x\n",
segtNo, cmd[0], cmd[1], cmd[2], cmd[3], cmd[4]);
break;
case EDL_PATCH_VER_REQ_CMD:
fprintf(stderr, "%s: Sending EDL_PATCH_VER_REQ_CMD\n", __FUNCTION__);
fprintf(stderr, "HCI-CMD %d:\t0x%x \t0x%x \t0x%x \t0x%x \t0x%x\n",
segtNo, cmd[0], cmd[1], cmd[2], cmd[3], cmd[4]);
break;
case EDL_PATCH_TLV_REQ_CMD:
fprintf(stderr, "%s: Sending EDL_PATCH_TLV_REQ_CMD\n", __FUNCTION__);
/* Parameter Total Length */
cmd[3] = size +2;
/* TLV Segment Length */
cmd[5] = size;
fprintf(stderr, "HCI-CMD %d:\t0x%x \t0x%x \t0x%x \t0x%x \t0x%x \t0x%x\n",
segtNo, cmd[0], cmd[1], cmd[2], cmd[3], cmd[4], cmd[5]);
offset = (segtNo * MAX_SIZE_PER_TLV_SEGMENT);
memcpy(&cmd[6], (pdata_buffer + offset), size);
break;
default:
fprintf(stderr, "%s: Unknown EDL CMD !!!\n", __FUNCTION__);
}
}
void rome_extract_patch_header_info(unsigned char *buf)
{
int index;
/* Extract patch id */
for (index = 0; index < 4; index++)
rampatch_patch_info.patch_id |=
(LSH(buf[index + P_ID_OFFSET], (index * 8)));
/* Extract (ROM and BUILD) version information */
for (index = 0; index < 2; index++)
rampatch_patch_info.patch_ver.rom_version |=
(LSH(buf[index + P_ROME_VER_OFFSET], (index * 8)));
for (index = 0; index < 2; index++)
rampatch_patch_info.patch_ver.build_version |=
(LSH(buf[index + P_BUILD_VER_OFFSET], (index * 8)));
/* Extract patch base and entry addresses */
for (index = 0; index < 4; index++)
rampatch_patch_info.patch_base_addr |=
(LSH(buf[index + P_BASE_ADDR_OFFSET], (index * 8)));
/* Patch BASE & ENTRY addresses are same */
rampatch_patch_info.patch_entry_addr = rampatch_patch_info.patch_base_addr;
/* Extract total length of the patch payload */
for (index = 0; index < 4; index++)
rampatch_patch_info.patch_length |=
(LSH(buf[index + P_LEN_OFFSET], (index * 8)));
/* Extract the CRC checksum of the patch payload */
for (index = 0; index < 4; index++)
rampatch_patch_info.patch_crc |=
(LSH(buf[index + P_CRC_OFFSET], (index * 8)));
/* Extract patch control value */
for (index = 0; index < 4; index++)
rampatch_patch_info.patch_ctrl |=
(LSH(buf[index + P_CONTROL_OFFSET], (index * 8)));
fprintf(stderr, "PATCH_ID\t : 0x%x\n", rampatch_patch_info.patch_id);
fprintf(stderr, "ROM_VERSION\t : 0x%x\n", rampatch_patch_info.patch_ver.rom_version);
fprintf(stderr, "BUILD_VERSION\t : 0x%x\n", rampatch_patch_info.patch_ver.build_version);
fprintf(stderr, "PATCH_LENGTH\t : 0x%x\n", rampatch_patch_info.patch_length);
fprintf(stderr, "PATCH_CRC\t : 0x%x\n", rampatch_patch_info.patch_crc);
fprintf(stderr, "PATCH_CONTROL\t : 0x%x\n", rampatch_patch_info.patch_ctrl);
fprintf(stderr, "PATCH_BASE_ADDR\t : 0x%x\n", rampatch_patch_info.patch_base_addr);
}
int rome_edl_set_patch_request(int fd)
{
int size, err;
unsigned char cmd[HCI_MAX_CMD_SIZE];
unsigned char rsp[HCI_MAX_EVENT_SIZE];
/* Frame the HCI CMD to be sent to the Controller */
frame_hci_cmd_pkt(cmd, EDL_PATCH_SET_REQ_CMD, 0,
-1, PATCH_HDR_LEN + 1);
/* Total length of the packet to be sent to the Controller */
size = (HCI_CMD_IND + HCI_COMMAND_HDR_SIZE + cmd[PLEN]);
/* Send HCI Command packet to Controller */
err = hci_send_vs_cmd(fd, (unsigned char *)cmd, rsp, size);
if ( err != size) {
fprintf(stderr, "Failed to set the patch info to the Controller!\n");
goto error;
}
err = read_hci_event(fd, rsp, HCI_MAX_EVENT_SIZE);
if ( err < 0) {
fprintf(stderr, "%s: Failed to set patch info on Controller\n", __FUNCTION__);
goto error;
}
fprintf(stderr, "%s: Successfully set patch info on the Controller\n", __FUNCTION__);
error:
return err;
}
int rome_edl_patch_download_request(int fd)
{
int no_of_patch_segment;
int index = 1, err = 0, size = 0;
unsigned int p_base_addr;
unsigned char cmd[HCI_MAX_CMD_SIZE];
unsigned char rsp[HCI_MAX_EVENT_SIZE];
no_of_patch_segment = (rampatch_patch_info.patch_length /
MAX_DATA_PER_SEGMENT);
fprintf(stderr, "%s: %d patch segments to be d'loaded from patch base addr: 0x%x\n",
__FUNCTION__, no_of_patch_segment,
rampatch_patch_info.patch_base_addr);
/* Initialize the patch base address from the one read from bin file */
p_base_addr = rampatch_patch_info.patch_base_addr;
/*
* Depending upon size of the patch payload, download the patches in
* segments with a max. size of 239 bytes
*/
for (index = 1; index <= no_of_patch_segment; index++) {
fprintf(stderr, "%s: Downloading patch segment: %d\n", __FUNCTION__, index);
/* Frame the HCI CMD PKT to be sent to Controller*/
frame_hci_cmd_pkt(cmd, EDL_PATCH_DLD_REQ_CMD, p_base_addr,
index, MAX_DATA_PER_SEGMENT);
/* Total length of the packet to be sent to the Controller */
size = (HCI_CMD_IND + HCI_COMMAND_HDR_SIZE + cmd[PLEN]);
/* Initialize the RSP packet everytime to 0 */
memset(rsp, 0x0, HCI_MAX_EVENT_SIZE);
/* Send HCI Command packet to Controller */
err = hci_send_vs_cmd(fd, (unsigned char *)cmd, rsp, size);
if ( err != size) {
fprintf(stderr, "Failed to send the patch payload to the Controller!\n");
goto error;
}
/* Read Command Complete Event */
err = read_hci_event(fd, rsp, HCI_MAX_EVENT_SIZE);
if ( err < 0) {
fprintf(stderr, "%s: Failed to downlaod patch segment: %d!\n",
__FUNCTION__, index);
goto error;
}
fprintf(stderr, "%s: Successfully downloaded patch segment: %d\n",
__FUNCTION__, index);
}
/* Check if any pending patch data to be sent */
size = (rampatch_patch_info.patch_length < MAX_DATA_PER_SEGMENT) ?
rampatch_patch_info.patch_length :
(rampatch_patch_info.patch_length % MAX_DATA_PER_SEGMENT);
if (size)
{
/* Frame the HCI CMD PKT to be sent to Controller*/
frame_hci_cmd_pkt(cmd, EDL_PATCH_DLD_REQ_CMD, p_base_addr, index, size);
/* Initialize the RSP packet everytime to 0 */
memset(rsp, 0x0, HCI_MAX_EVENT_SIZE);
/* Total length of the packet to be sent to the Controller */
size = (HCI_CMD_IND + HCI_COMMAND_HDR_SIZE + cmd[PLEN]);
/* Send HCI Command packet to Controller */
err = hci_send_vs_cmd(fd, (unsigned char *)cmd, rsp, size);
if ( err != size) {
fprintf(stderr, "Failed to send the patch payload to the Controller!\n");
goto error;
}
/* Read Command Complete Event */
err = read_hci_event(fd, rsp, HCI_MAX_EVENT_SIZE);
if ( err < 0) {
fprintf(stderr, "%s: Failed to downlaod patch segment: %d!\n",
__FUNCTION__, index);
goto error;
}
fprintf(stderr, "%s: Successfully downloaded patch segment: %d\n",
__FUNCTION__, index);
}
error:
return err;
}
static int rome_download_rampatch(int fd)
{
int c, size, index, ret = -1;
fprintf(stderr, "%s:\n", __FUNCTION__);
/* Get handle to the RAMPATCH binary file */
fprintf(stderr, "%s: Getting handle to the RAMPATCH binary file from %s\n", __FUNCTION__, ROME_FW_PATH);
file = fopen(ROME_FW_PATH, "r");
if (file == NULL) {
fprintf(stderr, "%s: Failed to get handle to the RAMPATCH bin file!\n",
__FUNCTION__);
return -ENFILE;
}
/* Allocate memory for the patch headder info */
fprintf(stderr, "%s: Allocating memory for the patch header\n", __FUNCTION__);
phdr_buffer = (unsigned char *) malloc(PATCH_HDR_LEN + 1);
if (phdr_buffer == NULL) {
fprintf(stderr, "%s: Failed to allocate memory for patch header\n",
__FUNCTION__);
goto phdr_alloc_failed;
}
for (index = 0; index < PATCH_HDR_LEN + 1; index++)
phdr_buffer[index] = 0x0;
/* Read 28 bytes of patch header information */
fprintf(stderr, "%s: Reading patch header info\n", __FUNCTION__);
index = 0;
do {
c = fgetc (file);
phdr_buffer[index++] = (unsigned char)c;
} while (index != PATCH_HDR_LEN);
/* Save the patch header info into local structure */
fprintf(stderr, "%s: Saving patch hdr. info\n", __FUNCTION__);
rome_extract_patch_header_info((unsigned char *)phdr_buffer);
/* Set the patch header info onto the Controller */
ret = rome_edl_set_patch_request(fd);
if (ret < 0) {
fprintf(stderr, "%s: Error setting the patchheader info!\n", __FUNCTION__);
goto pdata_alloc_failed;
}
/* Allocate memory for the patch payload */
fprintf(stderr, "%s: Allocating memory for patch payload\n", __FUNCTION__);
size = rampatch_patch_info.patch_length;
pdata_buffer = (unsigned char *) malloc(size+1);
if (pdata_buffer == NULL) {
fprintf(stderr, "%s: Failed to allocate memory for patch payload\n",
__FUNCTION__);
goto pdata_alloc_failed;
}
for (index = 0; index < size+1; index++)
pdata_buffer[index] = 0x0;
/* Read the patch data from Rampatch binary image */
fprintf(stderr, "%s: Reading patch payload from RAMPATCH file\n", __FUNCTION__);
index = 0;
do {
c = fgetc (file);
pdata_buffer[index++] = (unsigned char)c;
} while (c != EOF);
/* Downloading patches in segments to controller */
ret = rome_edl_patch_download_request(fd);
if (ret < 0) {
fprintf(stderr, "%s: Error downloading patch segments!\n", __FUNCTION__);
goto cleanup;
}
cleanup:
free(pdata_buffer);
pdata_alloc_failed:
free(phdr_buffer);
phdr_alloc_failed:
fclose(file);
return ret;
}
int rome_attach_rampatch(int fd)
{
int size, err;
unsigned char cmd[HCI_MAX_CMD_SIZE];
unsigned char rsp[HCI_MAX_EVENT_SIZE];
/* Frame the HCI CMD to be sent to the Controller */
frame_hci_cmd_pkt(cmd, EDL_PATCH_ATCH_REQ_CMD, 0,
-1, EDL_PATCH_CMD_LEN);
/* Total length of the packet to be sent to the Controller */
size = (HCI_CMD_IND + HCI_COMMAND_HDR_SIZE + cmd[PLEN]);
/* Send HCI Command packet to Controller */
err = hci_send_vs_cmd(fd, (unsigned char *)cmd, rsp, size);
if ( err != size) {
fprintf(stderr, "Failed to attach the patch payload to the Controller!\n");
goto error;
}
/* Read Command Complete Event */
err = read_hci_event(fd, rsp, HCI_MAX_EVENT_SIZE);
if ( err < 0) {
fprintf(stderr, "%s: Failed to attach the patch segment(s)\n", __FUNCTION__);
goto error;
}
error:
return err;
}
int rome_rampatch_reset(int fd)
{
int size, err = 0;
unsigned char cmd[HCI_MAX_CMD_SIZE];
struct timespec tm = { 0, 100*1000*1000 }; /* 100 ms */
/* Frame the HCI CMD to be sent to the Controller */
frame_hci_cmd_pkt(cmd, EDL_PATCH_RST_REQ_CMD, 0,
-1, EDL_PATCH_CMD_LEN);
/* Total length of the packet to be sent to the Controller */
size = (HCI_CMD_IND + HCI_COMMAND_HDR_SIZE + EDL_PATCH_CMD_LEN);
/* Send HCI Command packet to Controller */
err = write(fd, cmd, size);
if (err != size) {
fprintf(stderr, "%s: Send failed with ret value: %d\n", __FUNCTION__, err);
goto error;
}
/*
* Controller doesn't sends any response for the patch reset
* command. HOST has to wait for 100ms before proceeding.
*/
nanosleep(&tm, NULL);
error:
return err;
}
int get_value_from_config(char *file_path,char *param)
{
FILE *pfile = NULL;
char *line = NULL;
char *pch = NULL;
char param_str[PARAM_LEN];
int bytes_read = 0, position;
int ret = -1;
if (!file_path || !param) {
fprintf(stderr,"Invalid arguments\n");
return -EINVAL;
}
pfile = fopen(file_path, "r" );
if (!pfile) {
fprintf(stderr, "Failed to open %s\n", file_path);
return ret;
}
while (getline(&line, (size_t *)&bytes_read, pfile) > 0 ) {
if (line[0] != '#' && line[0] != '\n') {
pch = memchr(line, '=', strlen(line));
if (pch != NULL) {
position = pch - line;
strncpy(param_str, line, sizeof(param_str));
if (position >= sizeof(param_str))
position = sizeof(param_str) - 1;
if (strncmp(param_str, param, position) == 0) {
ret = atoi(pch + 1);
break;
}
}
}
}
/* getline() will allocate a buffer for storing the line. */
free(line);
fclose(pfile);
return ret;
}
int rome_get_tlv_file(char *file_path)
{
FILE * pFile;
long fileSize;
int readSize, nvm_length, nvm_index, i;
unsigned short nvm_tag_len;
tlv_patch_info *ptlv_header;
tlv_nvm_hdr *nvm_ptr;
unsigned char data_buf[PRINT_BUF_SIZE]={0,};
unsigned char *nvm_byte_ptr;
unsigned char bdaddr[6];
unsigned short pcm_value, ibs_value;
fprintf(stderr, "File Open (%s)\n", file_path);
pFile = fopen ( file_path , "r" );
if (pFile==NULL) {;
fprintf(stderr, "%s File Open Fail\n", file_path);
return -1;
}
/* Get File Size */
fseek (pFile , 0 , SEEK_END);
if((fileSize = ftell(pFile)) < 0) {
fprintf(stderr, "%s: fail to get current file position\n", file_path);
fclose(pFile);
return -1;
}
if(fileSize == 0) {
fprintf(stderr, "%s: no content in the file\n", file_path);
fclose(pFile);
return -1;
}
rewind (pFile);
pdata_buffer = (unsigned char*) malloc (sizeof(char)*fileSize);
if (pdata_buffer == NULL) {
fprintf(stderr, "Allocated Memory failed\n");
fclose (pFile);
return -1;
}
/* Copy file into allocated buffer */
readSize = fread (pdata_buffer,1,fileSize,pFile);
/* File Close */
fclose (pFile);
if (readSize != fileSize) {
fprintf(stderr, "Read file size(%d) not matched with actual file size (%ld bytes)\n",readSize,fileSize);
return -1;
}
ptlv_header = (tlv_patch_info *) pdata_buffer;
/* To handle different event between rampatch and NVM */
gTlv_type = ptlv_header->tlv_type;
gtlv_dwndcfg = ptlv_header->tlv.patch.dwnd_cfg;
if(ptlv_header->tlv_type == TLV_TYPE_PATCH){
fprintf(stderr, "====================================================\n");
fprintf(stderr, "TLV Type\t\t\t : 0x%x\n", ptlv_header->tlv_type);
fprintf(stderr, "Length\t\t\t : %d bytes\n", (ptlv_header->tlv_length1) |
(ptlv_header->tlv_length2 << 8) |
(ptlv_header->tlv_length3 << 16));
fprintf(stderr, "Total Length\t\t\t : %d bytes\n", ptlv_header->tlv.patch.tlv_data_len);
fprintf(stderr, "Patch Data Length\t\t\t : %d bytes\n",ptlv_header->tlv.patch.tlv_patch_data_len);
fprintf(stderr, "Signing Format Version\t : 0x%x\n", ptlv_header->tlv.patch.sign_ver);
fprintf(stderr, "Signature Algorithm\t\t : 0x%x\n", ptlv_header->tlv.patch.sign_algorithm);
fprintf(stderr, "Event Handling\t\t\t : 0x%x", ptlv_header->tlv.patch.dwnd_cfg);
fprintf(stderr, "Reserved\t\t\t : 0x%x\n", ptlv_header->tlv.patch.reserved1);
fprintf(stderr, "Product ID\t\t\t : 0x%04x\n", ptlv_header->tlv.patch.prod_id);
fprintf(stderr, "Rom Build Version\t\t : 0x%04x\n", ptlv_header->tlv.patch.build_ver);
fprintf(stderr, "Patch Version\t\t : 0x%04x\n", ptlv_header->tlv.patch.patch_ver);
fprintf(stderr, "Reserved\t\t\t : 0x%x\n", ptlv_header->tlv.patch.reserved2);
fprintf(stderr, "Patch Entry Address\t\t : 0x%x\n", (ptlv_header->tlv.patch.patch_entry_addr));
fprintf(stderr, "====================================================\n");
} else if(ptlv_header->tlv_type == TLV_TYPE_NVM) {
fprintf(stderr, "====================================================\n");
fprintf(stderr, "TLV Type\t\t\t : 0x%x\n", ptlv_header->tlv_type);
fprintf(stderr, "Length\t\t\t : %d bytes\n", nvm_length = (ptlv_header->tlv_length1) |
(ptlv_header->tlv_length2 << 8) |
(ptlv_header->tlv_length3 << 16));
if(nvm_length <= 0)
return readSize;
for(nvm_byte_ptr=(unsigned char *)(nvm_ptr = &(ptlv_header->tlv.nvm)), nvm_index=0;
nvm_index < nvm_length ; nvm_ptr = (tlv_nvm_hdr *) nvm_byte_ptr)
{
fprintf(stderr, "TAG ID\t\t\t : %d\n", nvm_ptr->tag_id);
fprintf(stderr, "TAG Length\t\t\t : %d\n", nvm_tag_len = nvm_ptr->tag_len);
fprintf(stderr, "TAG Pointer\t\t\t : %d\n", nvm_ptr->tag_ptr);
fprintf(stderr, "TAG Extended Flag\t\t : %d\n", nvm_ptr->tag_ex_flag);
/* Increase nvm_index to NVM data */
nvm_index+=sizeof(tlv_nvm_hdr);
nvm_byte_ptr+=sizeof(tlv_nvm_hdr);
/* Write BD Address */
if(nvm_ptr->tag_id == TAG_NUM_2 && read_bd_address(&bdaddr) == 0) {
memcpy(nvm_byte_ptr, bdaddr, 6);
fprintf(stderr, "Overriding default BD ADDR with user"
" programmed BD Address: %02x:%02x:%02x:%02x:%02x:%02x\n",
*nvm_byte_ptr, *(nvm_byte_ptr+1), *(nvm_byte_ptr+2),
*(nvm_byte_ptr+3), *(nvm_byte_ptr+4), *(nvm_byte_ptr+5));
}
if (nvm_ptr->tag_id == TAG_NUM_17) {
if ((ibs_value =
get_value_from_config(FW_CONFIG_FILE_PATH, "IBS")) >= 0) {
if (ibs_value == FWCONF_IBS_DISABLE) {
nvm_byte_ptr[FWCONF_IBS_VAL_OFFSET] &=
(~(FWCONF_IBS_ENABLE <<
FWCONF_IBS_VAL_BIT));
} else if (ibs_value == FWCONF_IBS_ENABLE) {
nvm_byte_ptr[FWCONF_IBS_VAL_OFFSET] |=
(FWCONF_IBS_ENABLE <<
FWCONF_IBS_VAL_BIT);
}
}
}
/* Read from file and check what PCM Configuration is required:
* Master = 0 /Slave = 1 */
/* Override PCM configuration */
if (nvm_ptr->tag_id == TAG_NUM_44) {
if ((pcm_value =
get_value_from_config(FW_CONFIG_FILE_PATH, "PCM")) >= 0) {
if (pcm_value == FWCONF_PCM_SLAVE) {
nvm_byte_ptr[FWCONF_PCM_MS_OFFSET_1] |=
(1 << FWCONF_PCM_ROLE_BIT_OFFSET);
nvm_byte_ptr[FWCONF_PCM_MS_OFFSET_2] |=
(1 << FWCONF_PCM_ROLE_BIT_OFFSET);
} else if (pcm_value == FWCONF_PCM_MASTER) {
nvm_byte_ptr[FWCONF_PCM_MS_OFFSET_1] &=
(~(1 << FWCONF_PCM_ROLE_BIT_OFFSET));
nvm_byte_ptr[FWCONF_PCM_MS_OFFSET_2] &=
(~(1 << FWCONF_PCM_ROLE_BIT_OFFSET));
}
}
}
for(i =0;(i<nvm_ptr->tag_len && (i*3 + 2) < PRINT_BUF_SIZE);i++)
snprintf((char *) data_buf, PRINT_BUF_SIZE, "%s%.02x ",
(char *)data_buf, *(nvm_byte_ptr + i));
fprintf(stderr, "TAG Data\t\t\t : %s\n", data_buf);
/* Clear buffer */
memset(data_buf, 0x0, PRINT_BUF_SIZE);
/* increased by tag_len */
nvm_index+=nvm_ptr->tag_len;
nvm_byte_ptr +=nvm_ptr->tag_len;
}
fprintf(stderr, "====================================================\n");
} else {
fprintf(stderr, "TLV Header type is unknown (%d) \n", ptlv_header->tlv_type);
}
return readSize;
}
int rome_tlv_dnld_segment(int fd, int index, int seg_size, unsigned char wait_cc_evt)
{
int size=0, err = -1;
unsigned char cmd[HCI_MAX_CMD_SIZE];
unsigned char rsp[HCI_MAX_EVENT_SIZE];
fprintf(stderr, "%s: Downloading TLV Patch segment no.%d, size:%d\n", __FUNCTION__, index, seg_size);
/* Frame the HCI CMD PKT to be sent to Controller*/
frame_hci_cmd_pkt(cmd, EDL_PATCH_TLV_REQ_CMD, 0, index, seg_size);
/* Total length of the packet to be sent to the Controller */
size = (HCI_CMD_IND + HCI_COMMAND_HDR_SIZE + cmd[PLEN]);
/* Initialize the RSP packet everytime to 0 */
memset(rsp, 0x0, HCI_MAX_EVENT_SIZE);
/* Send HCI Command packet to Controller */
err = hci_send_vs_cmd(fd, (unsigned char *)cmd, rsp, size);
if ( err != size) {
fprintf(stderr, "Failed to send the patch payload to the Controller! 0x%x\n", err);
return err;
}
if(wait_cc_evt) {
err = read_hci_event(fd, rsp, HCI_MAX_EVENT_SIZE);
if ( err < 0) {
fprintf(stderr, "%s: Failed to downlaod patch segment: %d!\n", __FUNCTION__, index);
return err;
}
}
fprintf(stderr, "%s: Successfully downloaded patch segment: %d\n", __FUNCTION__, index);
return err;
}
int rome_tlv_dnld_req(int fd, int tlv_size)
{
int total_segment, remain_size, i, err = -1;
unsigned char wait_cc_evt = FALSE;
total_segment = tlv_size/MAX_SIZE_PER_TLV_SEGMENT;
remain_size = (tlv_size < MAX_SIZE_PER_TLV_SEGMENT)?\
tlv_size: (tlv_size%MAX_SIZE_PER_TLV_SEGMENT);
fprintf(stderr, "%s: TLV size: %d, Total Seg num: %d, remain size: %d\n",
__FUNCTION__,tlv_size, total_segment, remain_size);
if (gTlv_type == TLV_TYPE_PATCH) {
/* Prior to Rome version 3.2(including inital few rampatch release of
* Rome 3.2), the event handling mechanism is ROME_SKIP_EVT_NONE. After
* few release of rampatch for Rome 3.2, the mechamism is changed to
* ROME_SKIP_EVT_VSE_CC. Rest of the mechanism is not used for now
*/
switch(gtlv_dwndcfg)
{
case ROME_SKIP_EVT_NONE:
wait_vsc_evt = TRUE;
wait_cc_evt = TRUE;
fprintf(stderr, "%s: Event handling type: ROME_SKIP_EVT_NONE", __func__);
break;
case ROME_SKIP_EVT_VSE_CC:
wait_vsc_evt = FALSE;
wait_cc_evt = FALSE;
fprintf(stderr, "%s: Event handling type: ROME_SKIP_EVT_VSE_CC", __func__);
break;
/* Not handled for now */
case ROME_SKIP_EVT_VSE:
case ROME_SKIP_EVT_CC:
default:
fprintf(stderr, "%s: Unsupported Event handling: %d", __func__, gtlv_dwndcfg);
break;
}
} else {
wait_vsc_evt = TRUE;
wait_cc_evt = TRUE;
}
for(i = 0; i < total_segment; i++) {
if((i+1) == total_segment) {
if ((rome_ver >= ROME_VER_1_1) && (rome_ver < ROME_VER_3_2) &&
(gTlv_type == TLV_TYPE_PATCH)) {
/* If the Rome version is from 1.1 to 3.1
* 1. No CCE for the last command segment but all other segment
* 2. All the command segments get VSE including the last one
*/
wait_cc_evt = !remain_size ? FALSE: TRUE;
} else if ((rome_ver == ROME_VER_3_2) && (gTlv_type == TLV_TYPE_PATCH)) {
/* If the Rome version is 3.2
* 1. None of the command segments receive CCE
* 2. No command segments receive VSE except the last one
* 3. If gtlv_dwndcfg is ROME_SKIP_EVT_NONE then the logic is
* same as Rome 2.1, 2.2, 3.0
*/
if (gtlv_dwndcfg == ROME_SKIP_EVT_NONE) {
wait_cc_evt = !remain_size ? FALSE: TRUE;
} else if (gtlv_dwndcfg == ROME_SKIP_EVT_VSE_CC) {
wait_vsc_evt = !remain_size ? TRUE: FALSE;
}
}
}
if((err = rome_tlv_dnld_segment(fd, i, MAX_SIZE_PER_TLV_SEGMENT, wait_cc_evt )) < 0)
goto error;
}
if ((rome_ver >= ROME_VER_1_1) && (rome_ver < ROME_VER_3_2) && (gTlv_type == TLV_TYPE_PATCH)) {
/* If the Rome version is from 1.1 to 3.1
* 1. No CCE for the last command segment but all other segment
* 2. All the command segments get VSE including the last one
*/
wait_cc_evt = remain_size ? FALSE: TRUE;
} else if ((rome_ver == ROME_VER_3_2) && (gTlv_type == TLV_TYPE_PATCH)) {
/* If the Rome version is 3.2
* 1. None of the command segments receive CCE
* 2. No command segments receive VSE except the last one
* 3. If gtlv_dwndcfg is ROME_SKIP_EVT_NONE then the logic is
* same as Rome 2.1, 2.2, 3.0
*/
if (gtlv_dwndcfg == ROME_SKIP_EVT_NONE) {
wait_cc_evt = remain_size ? FALSE: TRUE;
} else if (gtlv_dwndcfg == ROME_SKIP_EVT_VSE_CC) {
wait_vsc_evt = remain_size ? TRUE: FALSE;
}
}
if(remain_size) err =rome_tlv_dnld_segment(fd, i, remain_size, wait_cc_evt);
error:
return err;
}
int rome_download_tlv_file(int fd)
{
int tlv_size, err = -1;
/* Rampatch TLV file Downloading */
pdata_buffer = NULL;
if((tlv_size = rome_get_tlv_file(rampatch_file_path)) < 0)
goto error;
if((err =rome_tlv_dnld_req(fd, tlv_size)) <0 )
goto error;
if (pdata_buffer != NULL){
free (pdata_buffer);
pdata_buffer = NULL;
}
/* NVM TLV file Downloading */
if((tlv_size = rome_get_tlv_file(nvm_file_path)) < 0)
goto error;
if((err =rome_tlv_dnld_req(fd, tlv_size)) <0 )
goto error;
error:
if (pdata_buffer != NULL)
free (pdata_buffer);
return err;
}
int rome_1_0_nvm_tag_dnld(int fd)
{
int i, size, err = 0;
unsigned char rsp[HCI_MAX_EVENT_SIZE];
#if (NVM_VERSION >= ROME_1_0_100019)
unsigned char cmds[MAX_TAG_CMD][HCI_MAX_CMD_SIZE] =
{
/* Tag 2 */ /* BD Address */
{ /* Packet Type */HCI_COMMAND_PKT,
/* Opcode */ 0x0b,0xfc,
/* Total Len */ 9,
/* NVM CMD */ NVM_ACCESS_SET,
/* Tag Num */ 2,
/* Tag Len */ 6,
/* Tag Value */ 0x77,0x78,0x23,0x01,0x56,0x22
},
/* Tag 6 */ /* Bluetooth Support Features */
{ /* Packet Type */HCI_COMMAND_PKT,
/* Opcode */ 0x0b,0xfc,
/* Total Len */ 11,
/* NVM CMD */ NVM_ACCESS_SET,
/* Tag Num */ 6,
/* Tag Len */ 8,
/* Tag Value */ 0xFF,0xFE,0x8B,0xFE,0xD8,0x3F,0x5B,0x8B
},
/* Tag 17 */ /* HCI Transport Layer Setting */
{ /* Packet Type */HCI_COMMAND_PKT,
/* Opcode */ 0x0b,0xfc,
/* Total Len */ 11,
/* NVM CMD */ NVM_ACCESS_SET,
/* Tag Num */ 17,
/* Tag Len */ 8,
/* Tag Value */ 0x82,0x01,0x0E,0x08,0x04,0x32,0x0A,0x00
},
/* Tag 35 */
{ /* Packet Type */HCI_COMMAND_PKT,
/* Opcode */ 0x0b,0xfc,
/* Total Len */ 58,
/* NVM CMD */ NVM_ACCESS_SET,
/* Tag Num */ 35,
/* Tag Len */ 55,
/* Tag Value */ 0x40, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, 0x58, 0x59,
0x0E, 0x0E, 0x16, 0x16, 0x16, 0x1E, 0x26, 0x5F, 0x2F, 0x5F,
0x0E, 0x0E, 0x16, 0x16, 0x16, 0x1E, 0x26, 0x5F, 0x2F, 0x5F,
0x0C, 0x18, 0x14, 0x24, 0x40, 0x4C, 0x70, 0x80, 0x80, 0x80,
0x0C, 0x18, 0x14, 0x24, 0x40, 0x4C, 0x70, 0x80, 0x80, 0x80,
0x1B, 0x14, 0x01, 0x04, 0x48
},
/* Tag 36 */
{ /* Packet Type */HCI_COMMAND_PKT,
/* Opcode */ 0x0b,0xfc,
/* Total Len */ 15,
/* NVM CMD */ NVM_ACCESS_SET,
/* Tag Num */ 36,
/* Tag Len */ 12,
/* Tag Value */ 0x0F,0x00,0x03,0x03,0x03,0x03,0x00,0x00,0x03,0x03,0x04,0x00
},
/* Tag 39 */
{ /* Packet Type */HCI_COMMAND_PKT,
/* Opcode */ 0x0b,0xfc,
/* Total Len */ 7,
/* NVM CMD */ NVM_ACCESS_SET,
/* Tag Num */ 39,
/* Tag Len */ 4,
/* Tag Value */ 0x12,0x00,0x00,0x00
},
/* Tag 41 */
{ /* Packet Type */HCI_COMMAND_PKT,
/* Opcode */ 0x0b,0xfc,
/* Total Len */ 91,
/* NVM CMD */ NVM_ACCESS_SET,
/* Tag Num */ 41,
/* Tag Len */ 88,
/* Tag Value */ 0x15, 0x00, 0x00, 0x00, 0xF6, 0x02, 0x00, 0x00, 0x76, 0x00,
0x1E, 0x00, 0x29, 0x02, 0x1F, 0x00, 0x61, 0x00, 0x1A, 0x00,
0x76, 0x00, 0x1E, 0x00, 0x7D, 0x00, 0x40, 0x00, 0x91, 0x00,
0x06, 0x00, 0x92, 0x00, 0x03, 0x00, 0xA6, 0x01, 0x50, 0x00,
0xAA, 0x01, 0x15, 0x00, 0xAB, 0x01, 0x0A, 0x00, 0xAC, 0x01,
0x00, 0x00, 0xB0, 0x01, 0xC5, 0x00, 0xB3, 0x01, 0x03, 0x00,
0xB4, 0x01, 0x13, 0x00, 0xB5, 0x01, 0x0C, 0x00, 0xC5, 0x01,
0x0D, 0x00, 0xC6, 0x01, 0x10, 0x00, 0xCA, 0x01, 0x2B, 0x00,
0xCB, 0x01, 0x5F, 0x00, 0xCC, 0x01, 0x48, 0x00
},
/* Tag 42 */
{ /* Packet Type */HCI_COMMAND_PKT,
/* Opcode */ 0x0b,0xfc,
/* Total Len */ 63,
/* NVM CMD */ NVM_ACCESS_SET,
/* Tag Num */ 42,
/* Tag Len */ 60,
/* Tag Value */ 0xD7, 0xC0, 0x00, 0x00, 0x8F, 0x5C, 0x02, 0x00, 0x80, 0x47,
0x60, 0x0C, 0x70, 0x4C, 0x00, 0x00, 0x00, 0x01, 0x1F, 0x01,
0x42, 0x01, 0x69, 0x01, 0x95, 0x01, 0xC7, 0x01, 0xFE, 0x01,
0x3D, 0x02, 0x83, 0x02, 0xD1, 0x02, 0x29, 0x03, 0x00, 0x0A,
0x10, 0x00, 0x1F, 0x00, 0x3F, 0x00, 0x7F, 0x00, 0xFD, 0x00,
0xF9, 0x01, 0xF1, 0x03, 0xDE, 0x07, 0x00, 0x00, 0x9A, 0x01
},
/* Tag 84 */
{ /* Packet Type */HCI_COMMAND_PKT,
/* Opcode */ 0x0b,0xfc,
/* Total Len */ 153,
/* NVM CMD */ NVM_ACCESS_SET,
/* Tag Num */ 84,
/* Tag Len */ 150,
/* Tag Value */ 0x7C, 0x6A, 0x59, 0x47, 0x19, 0x36, 0x35, 0x25, 0x25, 0x28,
0x2C, 0x2B, 0x2B, 0x28, 0x2C, 0x28, 0x29, 0x28, 0x29, 0x28,
0x29, 0x29, 0x2C, 0x29, 0x2C, 0x29, 0x2C, 0x28, 0x29, 0x28,
0x29, 0x28, 0x29, 0x2A, 0x00, 0x00, 0x2C, 0x2A, 0x2C, 0x18,
0x98, 0x98, 0x98, 0x98, 0x1E, 0x1E, 0x1E, 0x1E, 0x1E, 0x1E,
0x1E, 0x13, 0x1E, 0x1E, 0x1E, 0x1E, 0x13, 0x13, 0x11, 0x13,
0x1E, 0x1E, 0x13, 0x12, 0x12, 0x12, 0x11, 0x12, 0x1F, 0x12,
0x12, 0x12, 0x10, 0x0C, 0x18, 0x0D, 0x01, 0x01, 0x01, 0x01,
0x01, 0x01, 0x01, 0x0C, 0x01, 0x01, 0x01, 0x01, 0x0D, 0x0D,
0x0E, 0x0D, 0x01, 0x01, 0x0D, 0x0D, 0x0D, 0x0D, 0x0F, 0x0D,
0x10, 0x0D, 0x0D, 0x0D, 0x0D, 0x10, 0x05, 0x10, 0x03, 0x00,
0x7E, 0x7B, 0x7B, 0x72, 0x71, 0x50, 0x50, 0x50, 0x00, 0x40,
0x60, 0x60, 0x30, 0x08, 0x02, 0x0F, 0x00, 0x01, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x08, 0x16, 0x16, 0x08, 0x08, 0x00,
0x00, 0x00, 0x1E, 0x34, 0x2B, 0x1B, 0x23, 0x2B, 0x15, 0x0D
},
/* Tag 85 */
{ /* Packet Type */HCI_COMMAND_PKT,
/* Opcode */ 0x0b,0xfc,
/* Total Len */ 119,
/* NVM CMD */ NVM_ACCESS_SET,
/* Tag Num */ 85,
/* Tag Len */ 116,
/* Tag Value */ 0x03, 0x00, 0x38, 0x00, 0x45, 0x77, 0x00, 0xE8, 0x00, 0x59,
0x01, 0xCA, 0x01, 0x3B, 0x02, 0xAC, 0x02, 0x1D, 0x03, 0x8E,
0x03, 0x00, 0x89, 0x01, 0x0E, 0x02, 0x5C, 0x02, 0xD7, 0x02,
0xF8, 0x08, 0x01, 0x00, 0x1F, 0x00, 0x0A, 0x02, 0x55, 0x02,
0x00, 0x35, 0x00, 0x00, 0x00, 0x00, 0x2A, 0xD7, 0x00, 0x00,
0x00, 0x1E, 0xDE, 0x00, 0x00, 0x00, 0x14, 0x0F, 0x0A, 0x0F,
0x0A, 0x0C, 0x0C, 0x0C, 0x0C, 0x04, 0x04, 0x04, 0x0C, 0x0C,
0x0C, 0x0C, 0x06, 0x06, 0x00, 0x02, 0x02, 0x02, 0x02, 0x02,
0x01, 0x00, 0x02, 0x02, 0x02, 0x02, 0x01, 0x00, 0x00, 0x00,
0x06, 0x0F, 0x14, 0x05, 0x47, 0xCF, 0x77, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0xAC, 0x7C, 0xFF, 0x40, 0x00, 0x00, 0x00,
0x12, 0x04, 0x04, 0x01, 0x04, 0x03
},
{TAG_END}
};
#elif (NVM_VERSION == ROME_1_0_6002)
unsigned char cmds[MAX_TAG_CMD][HCI_MAX_CMD_SIZE] =
{
/* Tag 2 */
{ /* Packet Type */HCI_COMMAND_PKT,
/* Opcode */ 0x0b,0xfc,
/* Total Len */ 9,
/* NVM CMD */ NVM_ACCESS_SET,
/* Tag Num */ 2,
/* Tag Len */ 6,
/* Tag Value */ 0x77,0x78,0x23,0x01,0x56,0x22 /* BD Address */
},
/* Tag 6 */
{ /* Packet Type */HCI_COMMAND_PKT,
/* Opcode */ 0x0b,0xfc,
/* Total Len */ 11,
/* NVM CMD */ NVM_ACCESS_SET,
/* Tag Num */ 6,
/* Tag Len */ 8,
/* Tag Value */ 0xFF,0xFE,0x8B,0xFE,0xD8,0x3F,0x5B,0x8B
},
/* Tag 17 */
{ /* Packet Type */HCI_COMMAND_PKT,
/* Opcode */ 0x0b,0xfc,
/* Total Len */ 11,
/* NVM CMD */ NVM_ACCESS_SET,
/* Tag Num */ 17,
/* Tag Len */ 8,
/* Tag Value */ 0x82,0x01,0x0E,0x08,0x04,0x32,0x0A,0x00
},
/* Tag 36 */
{ /* Packet Type */HCI_COMMAND_PKT,
/* Opcode */ 0x0b,0xfc,
/* Total Len */ 15,
/* NVM CMD */ NVM_ACCESS_SET,
/* Tag Num */ 36,
/* Tag Len */ 12,
/* Tag Value */ 0x0F,0x00,0x03,0x03,0x03,0x03,0x00,0x00,0x03,0x03,0x04,0x00
},
/* Tag 39 */
{ /* Packet Type */HCI_COMMAND_PKT,
/* Opcode */ 0x0b,0xfc,
/* Total Len */ 7,
/* NVM CMD */ NVM_ACCESS_SET,
/* Tag Num */ 39,
/* Tag Len */ 4,
/* Tag Value */ 0x12,0x00,0x00,0x00
},
/* Tag 41 */
{ /* Packet Type */HCI_COMMAND_PKT,
/* Opcode */ 0x0b,0xfc,
/* Total Len */ 199,
/* NVM CMD */ NVM_ACCESS_SET,
/* Tag Num */ 41,
/* Tag Len */ 196,
/* Tag Value */ 0x30,0x00,0x00,0x00,0xD5,0x00,0x0E,0x00,0xD6,0x00,0x0E,0x00,
0xD7,0x00,0x16,0x00,0xD8,0x00,0x16,0x00,0xD9,0x00,0x16,0x00,
0xDA,0x00,0x1E,0x00,0xDB,0x00,0x26,0x00,0xDC,0x00,0x5F,0x00,
0xDD,0x00,0x2F,0x00,0xDE,0x00,0x5F,0x00,0xE0,0x00,0x0E,0x00,
0xE1,0x00,0x0E,0x00,0xE2,0x00,0x16,0x00,0xE3,0x00,0x16,0x00,
0xE4,0x00,0x16,0x00,0xE5,0x00,0x1E,0x00,0xE6,0x00,0x26,0x00,
0xE7,0x00,0x5F,0x00,0xE8,0x00,0x2F,0x00,0xE9,0x00,0x5F,0x00,
0xEC,0x00,0x0C,0x00,0xED,0x00,0x08,0x00,0xEE,0x00,0x14,0x00,
0xEF,0x00,0x24,0x00,0xF0,0x00,0x40,0x00,0xF1,0x00,0x4C,0x00,
0xF2,0x00,0x70,0x00,0xF3,0x00,0x80,0x00,0xF4,0x00,0x80,0x00,
0xF5,0x00,0x80,0x00,0xF8,0x00,0x0C,0x00,0xF9,0x00,0x18,0x00,
0xFA,0x00,0x14,0x00,0xFB,0x00,0x24,0x00,0xFC,0x00,0x40,0x00,
0xFD,0x00,0x4C,0x00,0xFE,0x00,0x70,0x00,0xFF,0x00,0x80,0x00,
0x00,0x01,0x80,0x00,0x01,0x01,0x80,0x00,0x04,0x01,0x1B,0x00,
0x05,0x01,0x14,0x00,0x06,0x01,0x01,0x00,0x07,0x01,0x04,0x00,
0x08,0x01,0x00,0x00,0x09,0x01,0x00,0x00,0x0A,0x01,0x03,0x00,
0x0B,0x01,0x03,0x00
},
/* Tag 44 */
{ /* Packet Type */HCI_COMMAND_PKT,
/* Opcode */ 0x0b,0xfc,
/* Total Len */ 44,
/* NVM CMD */ NVM_ACCESS_SET,
/* Tag Num */ 44,
/* Tag Len */ 41,
/* Tag Value */ 0x6F,0x0A,0x00,0x00,0x00,0x00,0x00,0x50,0xFF,0x10,0x02,0x02,
0x01,0x00,0x14,0x01,0x06,0x28,0xA0,0x62,0x03,0x64,0x01,0x01,
0x0A,0x00,0x00,0x00,0x00,0x00,0x00,0xA0,0xFF,0x10,0x02,0x01,
0x00,0x14,0x01,0x02,0x03
},
{TAG_END}
};
#endif
fprintf(stderr, "%s: Start sending NVM Tags (ver: 0x%x)\n", __FUNCTION__, (unsigned int) NVM_VERSION);
for (i=0; (i < MAX_TAG_CMD) && (cmds[i][0] != TAG_END); i++)
{
/* Write BD Address */
if(cmds[i][TAG_NUM_OFFSET] == TAG_NUM_2){
memcpy(&cmds[i][TAG_BDADDR_OFFSET], vnd_local_bd_addr, 6);
fprintf(stderr, "BD Address: %.2x:%.2x:%.2x:%.2x:%.2x:%.2x\n",
cmds[i][TAG_BDADDR_OFFSET ], cmds[i][TAG_BDADDR_OFFSET + 1],
cmds[i][TAG_BDADDR_OFFSET + 2], cmds[i][TAG_BDADDR_OFFSET + 3],
cmds[i][TAG_BDADDR_OFFSET + 4], cmds[i][TAG_BDADDR_OFFSET + 5]);
}
size = cmds[i][3] + HCI_COMMAND_HDR_SIZE + 1;
/* Send HCI Command packet to Controller */
err = hci_send_vs_cmd(fd, (unsigned char *)&cmds[i][0], rsp, size);
if ( err != size) {
fprintf(stderr, "Failed to attach the patch payload to the Controller!\n");
goto error;
}
/* Read Command Complete Event - This is extra routine for ROME 1.0. From ROM 2.0, it should be removed. */
err = read_hci_event(fd, rsp, HCI_MAX_EVENT_SIZE);
if ( err < 0) {
fprintf(stderr, "%s: Failed to get patch version(s)\n", __FUNCTION__);
goto error;
}
}
error:
return err;
}
int rome_patch_ver_req(int fd)
{
int size, err = 0;
unsigned char cmd[HCI_MAX_CMD_SIZE];
unsigned char rsp[HCI_MAX_EVENT_SIZE];
/* Frame the HCI CMD to be sent to the Controller */
frame_hci_cmd_pkt(cmd, EDL_PATCH_VER_REQ_CMD, 0,
-1, EDL_PATCH_CMD_LEN);
/* Total length of the packet to be sent to the Controller */
size = (HCI_CMD_IND + HCI_COMMAND_HDR_SIZE + EDL_PATCH_CMD_LEN);
/* Send HCI Command packet to Controller */
err = hci_send_vs_cmd(fd, (unsigned char *)cmd, rsp, size);
if ( err != size) {
fprintf(stderr, "Failed to attach the patch payload to the Controller!\n");
goto error;
}
/* Read Command Complete Event - This is extra routine for ROME 1.0. From ROM 2.0, it should be removed. */
err = read_hci_event(fd, rsp, HCI_MAX_EVENT_SIZE);
if ( err < 0) {
fprintf(stderr, "%s: Failed to get patch version(s)\n", __FUNCTION__);
goto error;
}
error:
return err;
}
static void flow_control(int fd, int opt)
{
struct termios c_opt;
ioctl(fd, TIOCMGET, &c_opt);
c_opt.c_cc[VTIME] = 0; /* inter-character timer unused */
c_opt.c_cc[VMIN] = 0; /* blocking read until 8 chars received */
c_opt.c_cflag &= ~CSIZE;
c_opt.c_cflag |= (CS8 | CLOCAL | CREAD);
if (opt == MSM_ENABLE_FLOW_CTRL)
c_opt.c_cflag |= CRTSCTS;
else if (opt == MSM_DISABLE_FLOW_CTRL)
c_opt.c_cflag &= ~CRTSCTS;
else {
fprintf(stderr, "%s: Incorrect option passed for TIOCMSET\n", __func__);
return;
}
c_opt.c_iflag = IGNPAR;
c_opt.c_oflag = 0;
c_opt.c_lflag = 0;
ioctl(fd, TIOCMSET, &c_opt);
}
int rome_set_baudrate_req(int fd)
{
int size, err = 0;
unsigned char cmd[HCI_MAX_CMD_SIZE];
unsigned char rsp[HCI_MAX_EVENT_SIZE];
hci_command_hdr *cmd_hdr;
int flags;
memset(cmd, 0x0, HCI_MAX_CMD_SIZE);
cmd_hdr = (void *) (cmd + 1);
cmd[0] = HCI_COMMAND_PKT;
cmd_hdr->opcode = cmd_opcode_pack(HCI_VENDOR_CMD_OGF, EDL_SET_BAUDRATE_CMD_OCF);
cmd_hdr->plen = VSC_SET_BAUDRATE_REQ_LEN;
cmd[4] = BAUDRATE_3000000;
/* Total length of the packet to be sent to the Controller */
size = (HCI_CMD_IND + HCI_COMMAND_HDR_SIZE + VSC_SET_BAUDRATE_REQ_LEN);
/* Flow off during baudrate change */
flow_control(fd, MSM_DISABLE_FLOW_CTRL);
/* Send the HCI command packet to UART for transmission */
fprintf(stderr, "%s: HCI CMD: 0x%x 0x%x 0x%x 0x%x 0x%x\n", __FUNCTION__, cmd[0], cmd[1], cmd[2], cmd[3],cmd[4]) ;
err = write(fd, cmd, size);
if (err != size) {
fprintf(stderr, "%s: Send failed with ret value: %d\n", __FUNCTION__, err);
goto error;
}
/* Change Local UART baudrate to high speed UART */
userial_vendor_set_baud(USERIAL_BAUD_3M);
/* Flow on after changing local uart baudrate */
flow_control(fd, MSM_ENABLE_FLOW_CTRL);
/* Check for response from the Controller */
if ((err =read_vs_hci_event(fd, rsp, HCI_MAX_EVENT_SIZE)) < 0) {
fprintf(stderr, "%s: Failed to get HCI-VS Event from SOC\n", __FUNCTION__);
goto error;
}
fprintf(stderr, "%s: Received HCI-Vendor Specific Event from SOC\n", __FUNCTION__);
/* Wait for command complete event */
err = read_hci_event(fd, rsp, HCI_MAX_EVENT_SIZE);
if ( err < 0) {
fprintf(stderr, "%s: Failed to set patch info on Controller\n", __FUNCTION__);
goto error;
}
fprintf(stderr, "%s\n", __FUNCTION__);
error:
return err;
}
int rome_hci_reset_req(int fd)
{
int size, err = 0;
unsigned char cmd[HCI_MAX_CMD_SIZE];
unsigned char rsp[HCI_MAX_EVENT_SIZE];
hci_command_hdr *cmd_hdr;
int flags;
fprintf(stderr, "%s: HCI RESET \n", __FUNCTION__);
memset(cmd, 0x0, HCI_MAX_CMD_SIZE);
cmd_hdr = (void *) (cmd + 1);
cmd[0] = HCI_COMMAND_PKT;
cmd_hdr->opcode = HCI_RESET;
cmd_hdr->plen = 0;
/* Total length of the packet to be sent to the Controller */
size = (HCI_CMD_IND + HCI_COMMAND_HDR_SIZE);
/* Flow off during baudrate change */
flow_control(fd, MSM_DISABLE_FLOW_CTRL);
/* Send the HCI command packet to UART for transmission */
fprintf(stderr, "%s: HCI CMD: 0x%x 0x%x 0x%x 0x%x\n", __FUNCTION__, cmd[0], cmd[1], cmd[2], cmd[3]);
err = write(fd, cmd, size);
if (err != size) {
fprintf(stderr, "%s: Send failed with ret value: %d\n", __FUNCTION__, err);
goto error;
}
/* Change Local UART baudrate to high speed UART */
userial_vendor_set_baud(USERIAL_BAUD_3M);
/* Flow on after changing local uart baudrate */
flow_control(fd, MSM_ENABLE_FLOW_CTRL);
/* Wait for command complete event */
err = read_hci_event(fd, rsp, HCI_MAX_EVENT_SIZE);
if ( err < 0) {
fprintf(stderr, "%s: Failed to set patch info on Controller\n", __FUNCTION__);
goto error;
}
error:
return err;
}
int read_bd_address(unsigned char *bdaddr)
{
int fd = -1;
int readPtr = 0;
unsigned char data[BD_ADDR_LEN];
/* Open the persist file for reading device address*/
fd = open("/etc/bluetooth/.bt_nv.bin", O_RDONLY);
if(fd < 0)
{
fprintf(stderr, "%s: Open failed: Programming default BD ADDR\n", __func__);
return -1;
}
/* Read the NVM Header : fp will be advanced by readPtr number of bytes */
readPtr = read(fd, data, PERSIST_HEADER_LEN);
if (readPtr > 0)
fprintf(stderr, "%s: Persist header data: %02x \t %02x \t %02x\n", __func__,
data[NVITEM], data[RDWR_PROT], data[NVITEM_SIZE]);
else {
fprintf(stderr, "%s: Read from persist memory failed : Programming default"
" BD ADDR\n");
close(fd);
return -1;
}
/* Check for BD ADDR length before programming */
if(data[NVITEM_SIZE] != BD_ADDR_LEN) {
fprintf(stderr, "Invalid BD ADDR: Programming default BD ADDR!\n");
close(fd);
return -1;
}
/* Read the BD ADDR info */
readPtr = read(fd, data, BD_ADDR_LEN);
if (readPtr > 0)
fprintf(stderr, "BD-ADDR: ==> %02x:%02x:%02x:%02x:%02x:%02x\n", data[0],
data[1], data[2], data[3], data[4], data[5]);
else {
fprintf(stderr, "%s: Read from persist memory failed : Programming default"
" BD ADDR\n");
close(fd);
return -1;
}
memcpy(bdaddr, data, BD_ADDR_LEN);
close(fd);
return 0;
}
int qca_soc_init(int fd, char *bdaddr)
{
int err = -1;
int size;
vnd_userial.fd = fd;
#ifdef _PLATFORM_MDM_
/* Vote for UART CLK prior to FW download */
err = ioctl(fd, USERIAL_OP_CLK_ON);
if (err < 0) {
fprintf(stderr, "%s: Failed to vote UART CLK ON\n", __func__);
return -1;
}
#endif
/* Get Rome version information */
if((err = rome_patch_ver_req(fd)) <0){
fprintf(stderr, "%s: Fail to get Rome Version (0x%x)\n", __FUNCTION__, err);
goto error;
}
fprintf(stderr, "%s: Rome Version (0x%08x)\n", __FUNCTION__, rome_ver);
switch (rome_ver){
case ROME_VER_1_0:
{
/* Set and Download the RAMPATCH */
fprintf(stderr, "%s: Setting Patch Header & Downloading Patches\n", __FUNCTION__);
err = rome_download_rampatch(fd);
if (err < 0) {
fprintf(stderr, "%s: DOWNLOAD RAMPATCH failed!\n", __FUNCTION__);
goto error;
}
fprintf(stderr, "%s: DOWNLOAD RAMPTACH complete\n", __FUNCTION__);
/* Attach the RAMPATCH */
fprintf(stderr, "%s: Attaching the patches\n", __FUNCTION__);
err = rome_attach_rampatch(fd);
if (err < 0) {
fprintf(stderr, "%s: ATTACH RAMPATCH failed!\n", __FUNCTION__);
goto error;
}
fprintf(stderr, "%s: ATTACH RAMPTACH complete\n", __FUNCTION__);
/* Send Reset */
size = (HCI_CMD_IND + HCI_COMMAND_HDR_SIZE + EDL_PATCH_CMD_LEN);
err = rome_rampatch_reset(fd);
if ( err < 0 ) {
fprintf(stderr, "Failed to RESET after RAMPATCH upgrade!\n");
goto error;
}
/* NVM download */
fprintf(stderr, "%s: Downloading NVM\n", __FUNCTION__);
err = rome_1_0_nvm_tag_dnld(fd);
if ( err <0 ) {
fprintf(stderr, "Downloading NVM Failed !!\n");
goto error;
}
/* Change baud rate 115.2 kbps to 3Mbps*/
err = rome_hci_reset_req(fd);
if ( err <0 ) {
fprintf(stderr, "HCI Reset Failed !!\n");
goto error;
}
fprintf(stderr, "HCI Reset is done\n");
}
break;
case ROME_VER_1_1:
rampatch_file_path = ROME_RAMPATCH_TLV_PATH;
nvm_file_path = ROME_NVM_TLV_PATH;
goto download;
case ROME_VER_1_3:
rampatch_file_path = ROME_RAMPATCH_TLV_1_0_3_PATH;
nvm_file_path = ROME_NVM_TLV_1_0_3_PATH;
goto download;
case ROME_VER_2_1:
rampatch_file_path = ROME_RAMPATCH_TLV_2_0_1_PATH;
nvm_file_path = ROME_NVM_TLV_2_0_1_PATH;
goto download;
case ROME_VER_3_0:
rampatch_file_path = ROME_RAMPATCH_TLV_3_0_0_PATH;
nvm_file_path = ROME_NVM_TLV_3_0_0_PATH;
goto download;
case ROME_VER_3_2:
rampatch_file_path = ROME_RAMPATCH_TLV_3_0_2_PATH;
nvm_file_path = ROME_NVM_TLV_3_0_2_PATH;
goto download;
case TUFELLO_VER_1_0:
rampatch_file_path = TF_RAMPATCH_TLV_1_0_0_PATH;
nvm_file_path = TF_NVM_TLV_1_0_0_PATH;
download:
/* Change baud rate 115.2 kbps to 3Mbps*/
err = rome_set_baudrate_req(fd);
if (err < 0) {
fprintf(stderr, "%s: Baud rate change failed!\n", __FUNCTION__);
goto error;
}
fprintf(stderr, "%s: Baud rate changed successfully \n", __FUNCTION__);
/* Donwload TLV files (rampatch, NVM) */
err = rome_download_tlv_file(fd);
if (err < 0) {
fprintf(stderr, "%s: Download TLV file failed!\n", __FUNCTION__);
goto error;
}
fprintf(stderr, "%s: Download TLV file successfully \n", __FUNCTION__);
/* Perform HCI reset here*/
err = rome_hci_reset_req(fd);
if ( err <0 ) {
fprintf(stderr, "HCI Reset Failed !!!\n");
goto error;
}
fprintf(stderr, "HCI Reset is done\n");
break;
case ROME_VER_UNKNOWN:
default:
fprintf(stderr, "%s: Detected unknown ROME version\n", __FUNCTION__);
err = -1;
break;
}
error:
#ifdef _PLATFORM_MDM_
/* Vote UART CLK OFF post to FW download */
err = ioctl(fd, USERIAL_OP_CLK_OFF);
if (err < 0)
fprintf(stderr, "%s: Failed to vote UART CLK OFF!!!\n", __func__);
#endif
return err;
}