| /* |
| * 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; |
| } |