blob: 191b6b007c60d50bfa67a7992ce0d10c5db87c1d [file] [log] [blame]
/*
* Copyright (C) 2009/2010 Motorola Inc.
* All Rights Reserved.
* Motorola Confidential Restricted.
*/
#include <stdlib.h>
#include <stdio.h>
#include <errno.h>
#include <unistd.h>
#include <sys/types.h>
#include <fcntl.h>
#include <termios.h>
#include "common.h"
#include "masterclear_bp.h"
/* @ set usb in unsuspend mode */
int set_usb_unsuspend()
{
int ret;
int count = sizeof(setup_cmd)-1;
FILE *fp = fopen(USB1_SETUP_FILE, "w");
if (fp == NULL) {
LOGE("Can't open %s\n", USB1_SETUP_FILE);
fclose(fp);
return 1;
}
else {
if ((ret = fwrite(setup_cmd,1,count,fp))<count)
{
LOGE("Write %s failed.\n",USB1_SETUP_FILE);
fclose(fp);
return 1;
}
}
fclose(fp);
return 0;
}
/* @dump the buff data to debug */
void CMD_DBG_data_dump(void* databuff, int len)
{
#ifdef TC_DEBUG
int max_col = CMD_DBG_MAX_DUMP_COLS;
int row = 0;
int col = 0;
int num_col;
int buffer_index = 0;
UINT8 value;
char string_buffer[(TC_DBG_MAX_DUMP_COLS * 3) + 1]; /* Each column takes up 3 characters, plus NULL */
for (row = 0; row <= (len / max_col); row++)
{
/* Reset string buffer for each new row */
memset(string_buffer, 0, sizeof(string_buffer));
/* For all rows, the number of columns is the max number, except for the last row */
num_col = (row == (len / max_col)) ? (len % max_col) : max_col;
if (num_col != 0)
{
for (col = 0; col < num_col; col++)
{
value = ((UINT8*)databuff)[buffer_index++];
LOGE("%s%02x ", string_buffer, value);
}
LOGE("%s", string_buffer);
}
}
#endif
}
/*=============================================================================================*//**
@brief Initializes the communcation interface with the bp command engine
@return Status of initialization
@note
- If no command engine is present, CMD_ENGINE_INIT_NOT_PRESENT must be returned
*//*==============================================================================================*/
CMD_ENGINE_INIT_T CMD_ENGINE_init(void)
{
UINT8 try_count = 1;
CMD_ENGINE_INIT_T status = CMD_ENGINE_INIT_FAIL;
cmd_engine_fd = -1;
/* Keep trying to connect to the command engine until we are successful, or we hit the retry max */
usleep(4000000);
while (cmd_engine_fd < 0)
{
LOGE("open dev\n");
if ( (cmd_engine_fd = open (CMD_ENGINE_DEVICE, O_RDWR)) < 0 )
{
if (try_count == CMD_ENGINE_CONNECT_MAX_TRY)
{
LOGE("Reached max number of retries, giving up...\n");
break;
}
else
{
/* Try to connect again, wait a bit before retry */
try_count++;
usleep(CMD_ENGINE_CONNECT_TRY_DELAY);
}
}
else
{
struct termios tio;
tcgetattr( cmd_engine_fd, &tio );
/* Modify local options */
tio.c_lflag &= ~( ECHO | ECHOE | ECHOK | ECHONL ); // None ECHO mode
tio.c_lflag &= ~( ICANON | ISIG ); // raw data
/* Modify input options */
tio.c_iflag = IGNBRK | IGNPAR; //work code
/* Modify output options */
tio.c_oflag &= ~( OPOST ); // work code
/* Modify control options */
tio.c_cflag |= ( CLOCAL | CREAD | CRTSCTS ); //enable receiver & hardware flow control
tio.c_cflag &= ~( CSIZE ); //disable bit mask for data bits
tio.c_cflag |= CS8; //set 8-bit characters
tio.c_cflag &= ~( PARENB ); //disable parity bit*/
/* Modify the Baud Rate */
cfsetispeed( &tio, B115200 );
cfsetospeed( &tio, B115200 );
/* Clear the line and prepare to activate the new settings */
tcflush( cmd_engine_fd, TCIFLUSH );
/* Set the options */
tcsetattr( cmd_engine_fd, TCSANOW, &tio );
status = CMD_ENGINE_INIT_SUCCESS;
}
}
return(status);
}
/*=========================================================================*//*
brief read command response from bp
@param[in] bytes_to_write - The number of bytes to read
@param[out] data - Data to read
@return TRUE = success, FALSE = failure
*//*=================================================================================*/
BOOL CMD_ENGINE_read(UINT32 bytes_to_read, UINT8 *data)
{
BOOL is_success = FALSE;
UINT32 total_bytes_read = 0;
UINT32 bytes_read = 0;
/* Return error if the aux engine handle is not init'd */
if (cmd_engine_fd == CMD_ENGINE_FD_NOT_INIT)
{
LOGE(" engine device is not open!\n");
}
else
{
while( total_bytes_read != bytes_to_read )
{
bytes_read = read(cmd_engine_fd, &data[total_bytes_read], bytes_to_read - total_bytes_read);
LOGE("Attempted to read %d bytes and read %d bytes.\n", bytes_to_read - total_bytes_read, bytes_read);
if( bytes_read <= 0 )
{
LOGE("Failed to read engine device.\n");
break;
}
total_bytes_read += bytes_read;
}
if( total_bytes_read == bytes_to_read )
{
LOGE("Successfully read %d bytes.\n", total_bytes_read);
is_success = TRUE;
}
}
return (is_success);
}
/*=============================================================================================*//**
@brief Writes the specified number of bytes to the command engine
@param[in] bytes_to_write - The number of bytes to write
@param[out] data - Data to write
@return TRUE = success, FALSE = failure
@note
- The write is synchronous, the function will block until the requested number of bytes are written
*//*==============================================================================================*/
BOOL CMD_ENGINE_write(UINT32 bytes_to_write, UINT8 *data)
{
BOOL is_success = FALSE;
UINT32 bytes_wrote = 0;
/* Return error if the aux engine handle is not init'd */
if (cmd_engine_fd == CMD_ENGINE_FD_NOT_INIT)
{
LOGE("engine device is not open!\n");
}
else
{
bytes_wrote = write(cmd_engine_fd, data, bytes_to_write);
if (bytes_wrote != bytes_to_write)
{
LOGE("Failed to write to engine device, attempted to write %d bytes, but wrote %d.\n",bytes_to_write, bytes_wrote);
}
else
{
LOGE("Successfully wrote %d bytes.\n", bytes_wrote);
is_success = TRUE;
}
}
return (is_success);
}
/*=============================================================================================*//**
@brief Convert network byte order to host byte order for command request headers
@param[in] hdr_in - Network byte order command request header
@param[out] hdr_out - Host byte order command request header
*//*==============================================================================================*/
void CMD_ENGINE_UTIL_hdr_req_ntoh(CMD_DEFS_CMD_REQ_HDR_T* hdr_in,CMD_DEFS_CMD_REQ_HDR_T* hdr_out)
{
memcpy(hdr_out, hdr_in, sizeof(CMD_DEFS_CMD_REQ_HDR_T));
hdr_out->opcode = ((hdr_in->opcode & 0x00FF) << 8) | ((hdr_in->opcode & 0xFF00) >> 8);
hdr_out->length = ((hdr_in->length & 0x000000FF) << 24) |
((hdr_in->length & 0x0000FF00) << 8) |
((hdr_in->length & 0x00FF0000) >> 8) |
((hdr_in->length & 0xFF000000) >> 24);
}
/*================================================================*//**
@ brief change bp from flash mode to normal mode
*//*=================================================================*/
int bp_flashmode_to_normalmode(void)
{
int fd;
ssize_t result;
fd = open(MDM_CTRL_DEVICE, O_WRONLY);
if (fd < 0)
{
LOGE("failed open mdm_ctrl\n");
return fd;
}
LOGE("open mdm_ctrl ok\n");
//shutdown BP
// echo shutdown > /sys/class/radio/mdm6600/command
result = write(fd, MDM_CMD_SHUTDONW, sizeof(MDM_CMD_SHUTDONW)-1);
if (result < (ssize_t)(sizeof(MDM_CMD_SHUTDONW)-1))
{
LOGE("Failed to shutdown BP\n");
return -1;
}
usleep(1000000);
//set BP power up mode
// echo bootmode_normal > /sys/class/radio/mdm6600/command
result = write(fd, MDM_CMD_NORMAL_MODE, sizeof(MDM_CMD_NORMAL_MODE)-1);
if (result < (ssize_t)(sizeof(MDM_CMD_NORMAL_MODE)-1))
{
LOGE("Failed to set BP boot mode\n");
return -1;
}
//power up BP
// echo powerup > /sys/class/radio/mdm6600/command
result = write(fd, MDM_CMD_POWERUP, sizeof(MDM_CMD_POWERUP)-1);
if (result < (ssize_t)(sizeof(MDM_CMD_POWERUP)-1))
{
LOGE("Failed to powerup BP\n");
return -1;
}
usleep(2000000);
close(fd);
LOGE("Finished boot BP to normal mode\n");
return 0;
}
/*=============================================================================================*//**
@brief BP master clear
*//*==============================================================================================*/
int bp_master_clear(void)
{
UINT8 bp_ver_len;
const UINT8 *bp_rsp_data_ptr;
int write_len = 0;
int read_len = 0;
UINT8 *write_buff = NULL;
UINT8 *read_buff = NULL;
CMD_ENGINE_INIT_T aux_status;
CMD_DEFS_CMD_REQ_HDR_T cmd_header = {0};
CMD_DEFS_CMD_RSP_HDR_T c_rsp_hdr;
write_len = sizeof(CMD_DEFS_CMD_REQ_HDR_T);
/* Build up the CMD request */
cmd_header.cmd_rsp_flag = CMD_DEFS_HDR_FLAG_CMD_RSP_COMMAND;
cmd_header.opcode = CMD_CMN_DRV_BP_MASTERCLEAR_OPCODE;
cmd_header.no_rsp_reqd_flag = CMD_DEFS_HDR_FLAG_RESPONSE_EXPECTED;
cmd_header.length = CMD_BP_MASTER_RESET_DATALENTH;
/* cancel the usb suspend mode so that usb devices can be detected when bp power up */
if(set_usb_unsuspend()!=0)
{
LOGE("USB is suspended, master clear is ignored.\n");
return 1;
}
LOGE("finished unsuspend\n");
/* change bp from flash mode to normal mode*/
bp_flashmode_to_normalmode();
LOGE("from flash to normal mode\n");
/* Send the command and receive the response */
aux_status = CMD_ENGINE_init();
if (aux_status == CMD_ENGINE_INIT_NOT_PRESENT)
{
LOGE("Aux engine is not present, skipping engine setup.\n");
return 1;
}
else if (aux_status != CMD_ENGINE_INIT_SUCCESS)
{
LOGE("Failed to init the engine! aux_status = %d.\n", aux_status);
return 1;
}
LOGE("engine init finished\n");
write_len = sizeof(CMD_DEFS_CMD_REQ_HDR_T)+cmd_header.length;
if ( (write_buff = (UINT8 *)malloc(write_len)) == NULL)
{
LOGE("Out of memory - malloc failed on write_buff, length = %d.\n", write_len);
return 1;
}
CMD_ENGINE_UTIL_hdr_req_ntoh(&cmd_header, (CMD_DEFS_CMD_REQ_HDR_T *) write_buff);
write_buff[write_len-1] = CMD_BP_MASTER_CLEAR;
CMD_DBG_data_dump(write_buff, write_len);
if (CMD_ENGINE_write(write_len, write_buff) != TRUE)
{
LOGE("Write data to aux engine failed!\n");
return 1;
}
else
{
LOGE("Transferred %d byte(s) CMD opcode = 0x%04x to aux engine succeeded.\n",write_len, cmd_header.opcode);
}
LOGE("write finished\n");
free(write_buff);
/* Verify BP response was not a failure */
if (CMD_ENGINE_read(sizeof(c_rsp_hdr), (UINT8 *) &c_rsp_hdr) != TRUE)
{
LOGE("Reading header failed!\n");
return 1;
}
else
{
/* Network byte order to host byte order... */
CMD_DBG_data_dump(&c_rsp_hdr, sizeof(c_rsp_hdr));
}
if ( (c_rsp_hdr.fail_flag & CMD_DEFS_RSP_FLAG_FAIL) ||
( (c_rsp_hdr.rsp_code != CMD_RSP_CODE_CMD_RSP_GENERIC) &&
(c_rsp_hdr.rsp_code != CMD_RSP_CODE_NOT_SET) ) )
{
return 1;
}
close(cmd_engine_fd);
return 0;
}