/src/core/mid_statemachine.c
C | 2005 lines | 1569 code | 247 blank | 189 comment | 338 complexity | 1907af6e6ed7a4571f44b83629f26add MD5 | raw file
Possible License(s): Apache-2.0, LGPL-2.0, LGPL-2.1
Large files files are truncated, but you can click here to view the full file
- /*
- * Copyright (C) 2010 ST-Ericsson AS
- * Author: Erwan Bracq / erwan.bracq@stericsson.com
- *
- * 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.
- *
- * See the NOTICE file distributed with this work for additional
- * information regarding copyright ownership.
- */
- #include <mid_statemachine.h>
- #include <stdio.h>
- #include <stdlib.h>
- #include <string.h>
- #include <errno.h>
- #include <unistd.h>
- #include <private/android_filesystem_config.h>
- #include <sys/wait.h>
- #include <dlfcn.h>
- #include <time.h>
- #include <atchannel.h>
- #include <mid.h>
- #include <mid_caif.h>
- #include <mid_error.h>
- #include <mid_flash.h>
- #include <mid_gpio.h>
- #include <mid_ipc.h>
- #include <mid_log.h>
- #include <mid_mfa.h>
- #include <mid_power.h>
- #include <crash_dump.h>
- #include "mid_dev.h"
- #include "mid_sys.h"
- #define COUNTOF(A) (sizeof(A)/sizeof((A)[0]))
- typedef enum MID_Event_Oper_e {
- MID_CLEAR_EVENT,
- MID_KEEP_EVENT,
- } MID_Event_Oper_t;
- typedef MID_Event_Oper_t (*Transition_T)(struct mid * mid_info_p);
- typedef struct {
- MID_Event_t event;
- Transition_T func;
- } Event_Func_t;
- typedef struct {
- Event_Func_t *event_func_info;
- int timeout_value;
- } State_Entry_t;
- static mid_fw_upgr_error_code_t mid_fw_upgr_errors[] = {
- {"SYSTEM_ERROR", MID_FW_UPGR_RSLT_SYSTEM_ERROR},
- {"INVALID_REQ_PHASE", MID_FW_UPGR_RSLT_INVALID_REQ_PHASE},
- {"REQ_IN_PROGRESS", MID_FW_UPGR_RSLT_REQ_IN_PROGRESS},
- {"UNSUPP_MODEM", MID_FW_UPGR_RSLT_UNSUPP_MODEM},
- {"MODEM_SHUTDOWN", MID_FW_UPGR_RSLT_MODEM_SHUTDOWN},
- {"AT_TIMEOUT", MID_FW_UPGR_RSLT_AT_TIMEOUT},
- {"REQ_REJECTED", MID_FW_UPGR_RSLT_REJECTED},
- {"AT_CHN_ERROR", MID_FW_UPGR_RSLT_AT_CHN_ERROR},
- {"AT_CMD_ERROR", MID_FW_UPGR_RSLT_AT_CMD_ERROR},
- {"INVALID_MODEM_STATE",MID_FW_UPGR_RSLT_INVALID_MODEM_STATE},
- {"FILESYS_ERROR", MID_FW_UPGR_RSLT_FS_ERROR},
- {"IMG_SIZE_ERROR", MID_FW_UPGR_RSLT_IMG_SIZE_ERROR},
- {"LOW_BATTERY", MID_FW_UPGR_RSLT_LOW_BATT},
- {"NO_FW_IMG", MID_FW_UPGR_RSLT_NO_FW_IMG},
- };
- static const char * const MID_EventNames[] =
- {
- "MID_IPC_RBT_EVT",
- "MID_GPIO_RST2_EVT",
- "MID_GPIO_PRST_EVT",
- "MID_MODEM_HALT_EVT",
- "MID_MODEM_START_EVT",
- "MID_SIG_KILL_EVT",
- "MID_LONG_OPS_EVT",
- "MID_CFRDY_EVT",
- "MID_HIGH_TEMPERATURE_EVT",
- "MID_LOW_BATTERY_EVT",
- "MID_AT_CFUN0_EVT",
- "MID_AT_CFUN100_EVT",
- "MID_IPC_FW_UPGR_IMG_XFER_EVT",
- "MID_IPC_FW_UPGR_FLASH_EVT",
- "MID_IPC_FW_UPGR_STATUS_EVT",
- "MID_FW_XFER_OPS_EVT",
- "MID_FW_XFER_PROGRESS_EVT",
- "MID_TIMEOUT_EVT",
- "MID_FLASH_START_EVT",
- "MID_FLASH_END_EVT",
- "MID_LAST_EVT",
- };
- static const char * const MID_StateNames[] =
- {
- "STATE_OFF",
- "STATE_BOOT",
- "STATE_MODINF_UP",
- "STATE_ON",
- "STATE_DUMP",
- "STATE_SHUTDOWN",
- "STATE_FLASHING",
- };
- bool mid_statemachine_get_event_by_name(const char* name, MID_Event_t* event)
- {
- MID_Event_t i;
- for(i=MID_IPC_RBT_EVT; i<=MID_LAST_EVT; i++)
- if(strcmp(name, MID_EventNames[i])==0) {
- *event=i;
- return true;
- }
- return false;
- }
- // Helper functions
- static inline void lock_mid_data(struct mid* mid_info)
- {
- apr_status_t status;
- if (unlikely((status = apr_thread_mutex_lock(mid_info->mutex)) != APR_SUCCESS)) {
- char message[100];
- MLGE("MID: MID Unable to take internal mid data mutex: %s",
- apr_strerror(status, message, sizeof(message)));
- }
- }
- static inline void unlock_mid_data(struct mid* mid_info)
- {
- apr_status_t status;
- if (unlikely((status = apr_thread_mutex_unlock(mid_info->mutex)) != APR_SUCCESS)) {
- char message[100];
- MLGE("MID: MID Unable to release internal mid data mutex: %s",
- apr_strerror(status, message, sizeof(message)));
- }
- }
- #define LOCK_MID_DATA lock_mid_data(mid_info)
- #define UNLOCK_MID_DATA unlock_mid_data(mid_info)
- static char * mid_fw_upgrade_get_error_str(struct mid* mid_info, int error_code)
- {
- char * ret = NULL;
- int i;
- unsigned char num_codes
- = sizeof(mid_fw_upgr_errors) / sizeof(mid_fw_upgr_error_code_t);
- for (i = 0; i < num_codes; i++) {
- if (mid_fw_upgr_errors[i].error_code == error_code)
- break;
- }
- if (i < num_codes)
- ret = mid_fw_upgr_errors[i].str;
- else
- ret = mid_info->moli_fw_upgr_get_error_str(mid_info, error_code);
- return ret;
- }
- static const char* get_reason_from_last_event(struct mid* mid_info)
- {
- switch(mid_info->cur_event) {
- case MID_IPC_RBT_EVT: return "ipc";
- case MID_GPIO_RST2_EVT: return "rst2";
- case MID_GPIO_PRST_EVT: return "prst";
- case MID_MODEM_HALT_EVT: return "modem_halt";
- case MID_MODEM_START_EVT: return "modem_start";
- case MID_SIG_KILL_EVT: return "kill";
- case MID_LONG_OPS_EVT: return "long_op";
- case MID_CFRDY_EVT: return "caif_ready";
- case MID_HIGH_TEMPERATURE_EVT: return "temp";
- case MID_LOW_BATTERY_EVT: return "battery";
- case MID_AT_CFUN0_EVT: return "cfun=0";
- case MID_AT_CFUN100_EVT: return "cfun=100";
- case MID_IPC_FW_UPGR_IMG_XFER_EVT: return "fw_upgrade_xfer";
- case MID_IPC_FW_UPGR_FLASH_EVT: return "fw_upgrade_flash";
- case MID_IPC_FW_UPGR_STATUS_EVT: return "fw_upgrade_status";
- case MID_FW_XFER_OPS_EVT: return "fw_upgrade_op";
- case MID_FW_XFER_PROGRESS_EVT: return "fw_upgrade_progress";
- case MID_TIMEOUT_EVT: return "timeout";
- case MID_FLASH_START_EVT: return "flash_start";
- case MID_FLASH_END_EVT: return "flash_end";
- case MID_LAST_EVT:
- default: return "[unknown]";
- }
- }
- static int state_all_act_shutdown(struct mid* mid_info, int sendCfun)
- {
- int res = 0;
- union ipc_msg msg;
- ATResponse *atresponse = NULL;
- MLGD("STMACH: MID execute Action: Shutdown.");
- /* Notify other AT client that a shutdown is nearby. */
- ipc_prepare_message(&msg, STATECHANGE, "prepare_off", get_reason_from_last_event(mid_info));
- ipc_send_message(msg);
- MLGD("STMACH: MID sent prepare_off message. A modem shutdown is coming.");
- /* Special case - no PWRRSTIN available, we can use RESOUT2 to check if modem is alive under specific conditions. */
- if (unlikely(!mid_gpio_get_value(mid_info->gpios, GPIO_ID_RESOUT2) && mid_gpio_used(mid_info->gpios, GPIO_ID_RESOUT2) && !mid_gpio_used(mid_info->gpios, GPIO_ID_PWRRSTIN))) {
- if (!mid_gpio_used(mid_info->gpios, GPIO_ID_PWRRSTIN) && mid_info->modem_is_on == 0) {
- MLGD("MID: Modem is already down according GPIO RESOUT2 level - MID will now cut power.");
- goto modem_already_off;
- }
- }
- /* Normal case - PWRRSTIN is used to check if modem is on or off. */
- if (unlikely(!mid_gpio_get_value(mid_info->gpios, GPIO_ID_PWRRSTIN) && mid_gpio_used(mid_info->gpios, GPIO_ID_PWRRSTIN))) {
- MLGD("MID: Modem is already down according GPIO PWRRSTIN level - MID will now cut power.");
- goto modem_already_off;
- }
- /* If AT channel is available. Use it to power down with AT+CFUN commands. */
- if ((mid_info->at_chnl_fd >= 0) && (sendCfun)) {
- int *fd = &(mid_info->at_chnl_fd);
- int written = 0;
- MLGD("MID: AT channel available. Try to shutdown with AT commands.");
- /* Case where we got a AT+CFUN=0 requested on another AT channel. A modem reboot is trigged. */
- if (FLAG_UP(mid_info->event, MID_AT_CFUN0_EVT) &&
- mid_info->config->enable_efwd_atcfun) {
- /* Send OK response to command CFUN=0 on other channel. */
- MLGD("AT: >>> Forward command reply for CFUN=: %s", mid_info->at_cfun0_resp);
- written = write(*fd, mid_info->at_cfun0_resp, strlen(mid_info->at_cfun0_resp));
- if (written != (int)strlen(mid_info->at_cfun0_resp)) {
- MLGW("AT: >>> Failure on AT+CFUN forwarded command.");
- }
- free(mid_info->at_cfun0_resp);
- /* Toggle a reboot event */
- MLGD("STMACH: MID_IPC_RBT_EVT event set");
- SET_FLAG(mid_info->event, MID_IPC_RBT_EVT);
- }
- /* Case for AT+CFUN=100 enabled modem. */
- if (mid_info->prep_for_shutdown) {
- /* AT+CFUN=100 is done if we use a OnSwC modem or flashless configuration. */
- if (mid_info->config->use_on_sw_c || mid_info->config->initial_enable_bootldr) {
- MLGD("AT: >>> Execute AT+CFUN=100.");
- res = at_send_command("AT+CFUN=100", &atresponse);
- if (res < 0 || atresponse->success == 0) {
- MLGW("AT: >>> Failure on AT+CFUN command.");
- }
- at_response_free(atresponse);
- }
- /* Case where we got a AT+CFUN=100 requested on another AT channel. */
- if (FLAG_UP(mid_info->event, MID_AT_CFUN100_EVT) &&
- mid_info->config->enable_efwd_atcfun) {
- /* Send OK response to command CFUN=100 on other channel. */
- MLGD("AT: >>> Forward command reply for CFUN=: %s", mid_info->at_cfun100_resp);
- written = write(*fd, mid_info->at_cfun100_resp, strlen(mid_info->at_cfun100_resp));
- if (written != (int)strlen(mid_info->at_cfun100_resp)) {
- MLGW("AT: >>> Failure on AT+CFUN forwarded command.");
- }
- free(mid_info->at_cfun100_resp);
- }
- /* If we force it, AT+CFUN=0 is used to shutdown. Typical case is OnSwA modem. */
- if (mid_info->config->use_atcfun0) {
- MLGD("AT: >>> Execute AT+CFUN=0.");
- res = at_send_command("AT+CFUN=0", &atresponse);
- if (res < 0 || atresponse->success == 0) {
- MLGW("AT: >>> Failure on AT+CFUN command.");
- }
- at_response_free(atresponse);
- }
- } else {
- /* Case for non AT+CFUN=100 enabled modem. */
- MLGD("AT: >>> Execute AT+CFUN=0.");
- res = at_send_command("AT+CFUN=0", &atresponse);
- if (res < 0 || atresponse->success == 0) {
- MLGW("AT: >>> Failure on AT+CFUN command.");
- }
- at_response_free(atresponse);
- }
- } else {
- /* Modem is on, but we don t have AT channel, so we need to force power off via GPIO */
- res = 1;
- }
- modem_already_off:
- if ((mid_info->config->enable_at_channel) && (mid_info->at_chnl_fd >= 0))
- mid_at_chnl_close(mid_info);
- return res;
- }
- int state_all_evt_sig_kill(struct mid* mid_info)
- {
- int res = 0;
- apr_status_t status;
- MLGD("STMACH: MID execute Action: SIG_KILL processing.");
- CLEAR_FLAG(mid_info->event, MID_SIG_KILL_EVT);
- MLGD("STMACH: MID_SIG_KILL_EVT event cleared.");
- if (mid_info->config->enable_at_channel && (mid_info->at_chnl_fd >= 0))
- mid_at_chnl_close(mid_info);
- mid_enable_gpio_out_safe_mode(mid_info);
- if(mid_info->gpios) mid_gpio_release_all(mid_info->gpios);
- /* Disconnect IPC */
- res = ipc_medium_disconnect();
- if (unlikely(res != 0))
- MLGE("MID: Unable to stop IPC");
- #ifdef DEBUG_TRACE
- if (unlikely(mid_dbg_info.log_fd != NULL)) {
- res = fclose(mid_dbg_info.log_fd);
- mid_dbg_info.log_fd = NULL;
- if (res)
- MLGE("MID: Unable to close LOG file");
- }
- #endif
- /* TODO check how to clean up - If used by config, after a destroy, the value is not 0 or NULL
- if used by command line, a malloc is done
- if (mid_info->cfgfile != NULL)
- free(mid_info->cfgfile);
- if (mid_info->rdir != NULL)
- free(mid_info->rdir);
- */
- if (mid_info->dl_handle != NULL)
- dlclose(mid_info->dl_handle);
- /* Clean up everything */
- status = apr_thread_mutex_destroy(mid_info->mutex);
- if (unlikely(status != APR_SUCCESS)) {
- char message[100];
- MLGE("MID: Unable to destroy internal mid data mutex: %s",
- apr_strerror(status, message, sizeof(message)));
- }
- MLGD("MID: MID ended.");
- exit(EXIT_SUCCESS);
- }
- static int modem_power_off(struct mid* mid_info)
- {
- int res = 0;
- MLGD("STMACH: MID execute power OFF sequence");
- /* Have to put IO in safe mode before power off in order to prevent leakage */
- mid_enable_io_safe_mode(mid_info);
- if (mid_info->config->use_on_sw_c) {
- /* OnSwC */
- MLGD("GPIO: Using OnSwC");
- MLGD("GPIO: De-assert MOD ON pin");
- res = mid_gpio_deassert(mid_info->gpios, GPIO_ID_ON);
- if (unlikely(res)) {
- MLGE("GPIO: Can't deassert GPIO_ON");
- return -EMIDGPIO;
- }
- } else {
- /* OnSwA */
- MLGD("GPIO: Using OnSwA");
- MLGD("GPIO: Assert MOD ON pin");
- res = mid_gpio_assert(mid_info->gpios, GPIO_ID_ON);
- if (unlikely(res)) {
- MLGE("GPIO: Can't assert GPIO_ON");
- return -EMIDGPIO;
- }
- MLGD("GPIO: OnSwa long assert: %d seconds.", MODEM_POWER_OFF_LAT);
- sleep(MODEM_POWER_OFF_LAT);
- MLGD("GPIO: De-assert MOD ON pin");
- res = mid_gpio_deassert(mid_info->gpios, GPIO_ID_ON);
- if (unlikely(res)) {
- MLGE("GPIO: Can't deassert GPIO_ON");
- return -EMIDGPIO;
- }
- }
- MLGD("GPIO: De-assert PWRRSTOUT pin");
- usleep(2000);
- if (unlikely(mid_gpio_deassert(mid_info->gpios, GPIO_ID_PWRRSTOUT))) {
- MLGE("GPIO: Can't deassert GPIO_PWRRSTOUT");
- return -EMIDGPIO;
- }
- MLGD("STMACH: MID will be idle for 50 millisecond to allow safe mode propagation on IOs.");
- usleep(50000);
- return 0;
- }
- void shutdown_modem(struct mid* mid_info)
- {
- int ko_shutdown_result = 0;
- ssize_t maxwaittime = 100; /* Number of iteration in 50msec unit. Total is 50*100 = 5 sec */
- ssize_t reloadmaxwaittime = 20; /* Releoad timeout for 1 second on wrong shutdown operation */
- union ipc_msg msg;
- MLGD("STMACH: MID execute shutdown modem sequence");
- /* Signal all utility threads to shut down */
- mid_info->kill_threads = 1;
- /* Shutdown during fw upgrade flashing */
- /* If we fore some reason hasn't answered the IPCDB request for flashing we send a response now. */
- if (mid_info->fw_upgr_flash_reply_msg) {
- const char *errorstr = mid_fw_upgrade_get_error_str(mid_info,mid_info->fw_upgr_last_error);
- if (ipc_send_async_reply(&mid_info->fw_upgr_flash_reply_msg,
- (errorstr ? errorstr : "ERROR")))
- MLGE("MID: Failed to send fw upgrade error reply");
- }
- ko_shutdown_result = state_all_act_shutdown(mid_info, 1);
- /* After this point, AT channel is closed or not available */
- if (ko_shutdown_result)
- MLGW("MID: AT command not available to shutdown. Modem will be killed via GPIO control.");
- /* Time to execute Off command. If we do this after powering off we will have leakage. */
- MLGD("Cleaning up drivers before powering off in order to prevent leakage when power off modem");
- (void)my_system(mid_info, mid_info->config->mod_off_cmd);
- /* Power off the modem via ONSWa or ONSWc now */
- /* To poweroff the following condition should apply :
- * - GPIO RESOUT2 or GPIO PWRRSTIN used and high
- * - Prepare for shutdown enabled modem (AT+CFUN=100) and no forced AT+CFUN=0 shutdown command
- * OR
- * - Error on AT commands (ko_shutdown_result condition)
- *
- * For forced AT+CFUN=0 shutdown command (use_atcfun=0 condition) or "non prepare for shutdown" enabled modem
- * the standard way to shutdown is AT+CFUN=0. The modem will turn off by itself.
- */
- if (((mid_info->prep_for_shutdown && !mid_info->config->use_atcfun0) || ko_shutdown_result)
- && ((mid_gpio_used(mid_info->gpios, GPIO_ID_RESOUT2) && mid_gpio_get_value(mid_info->gpios, GPIO_ID_RESOUT2))
- || (mid_gpio_used(mid_info->gpios, GPIO_ID_PWRRSTIN) && mid_gpio_get_value(mid_info->gpios, GPIO_ID_PWRRSTIN))))
- if (modem_power_off(mid_info))
- MLGE("STMACH: Trouble in power off sequence. Modem may not be switched Off.");
- /* Last paranoiac check - PWRRSTIN & RESOUT2 should be low for prepare_for_shutdown enabled modem */
- if (unlikely(mid_gpio_get_value(mid_info->gpios, GPIO_ID_RESOUT2) || mid_gpio_get_value(mid_info->gpios, GPIO_ID_PWRRSTIN))) {
- /* If they don't MID will report error */
- if (mid_info->prep_for_shutdown && !mid_info->config->use_atcfun0) {
- if (mid_info->config->modem_arch_id == OSMIUM) {
- /* An insane case, DBB is powered off but ABB not. */
- if (!(mid_gpio_used(mid_info->gpios, GPIO_ID_RESET) && (mid_gpio_assert(mid_info->gpios, GPIO_ID_RESET)))) {
- MLGE("STMACH: Modem is not powered off after GPIO_RESET sequence. This is a MODEM bug - MID will be out of sync.");
- #if defined(MOTOROLA_FEATURE)
- mid_statemachine_log_panic_apr("Subtype: Modem is not powered off after GPIO_RESET sequence.\n", mid_info->config->critical_panic_detection_file);
- #endif
- mid_platform_reboot(mid_info);
- }
- }
- else {
- MLGE("STMACH: Modem is not powered off after GPIO_ON sequence. This is a MODEM bug - MID will be out of sync.");
- #if defined(MOTOROLA_FEATURE)
- mid_statemachine_log_panic_apr("Subtype: Modem is not powered off after GPIO_ON sequence.\n", mid_info->config->critical_panic_detection_file);
- #endif
- mid_platform_reboot(mid_info);
- }
- }
- }
- /* Special case to call a GPIO forced power off */
- if (mid_info->config->force_gpio_pwroff)
- modem_power_off(mid_info);
- /* Active loop to wait modem shutdown completion. Modem should be already off here, except if AT+CFUN=0 command is used with success
- * Then we let 5 sec to modem to complete power down.
- */
- while ((mid_gpio_used(mid_info->gpios, GPIO_ID_RESOUT2) && mid_gpio_get_value(mid_info->gpios, GPIO_ID_RESOUT2))
- || (mid_gpio_used(mid_info->gpios, GPIO_ID_PWRRSTIN) && mid_gpio_get_value(mid_info->gpios, GPIO_ID_PWRRSTIN))) {
- /* Sleep 50 milliseconds */
- usleep(50000); /* Poll every 50msec */
- maxwaittime--;
- if (maxwaittime == 0) {
- MLGE("STMACH: Modem shutdown timeout.");
- if (mid_info->config->modem_arch_id == OSMIUM) {
- /* An insane case, DBB is powered off but ABB not. */
- if (!(mid_gpio_used(mid_info->gpios, GPIO_ID_RESET) && (mid_gpio_assert(mid_info->gpios, GPIO_ID_RESET)))) {
- MLGE("STMACH: Modem is not powered off after GPIO_RESET sequence. This is a MODEM bug - MID will be out of sync.");
- MLGE("GPIO: GPIO_ID_RESOUT2 STATUS :%d", mid_gpio_get_value(mid_info->gpios, GPIO_ID_RESOUT2));
- MLGE("GPIO: GPIO_ID_PWRRSTIN STATUS :%d", mid_gpio_get_value(mid_info->gpios, GPIO_ID_PWRRSTIN));
- #if defined(MOTOROLA_FEATURE)
- mid_statemachine_log_panic_apr("Subtype: Modem is not powered off after GPIO_RESET sequence and shutdown timeout.\n", mid_info->config->critical_panic_detection_file);
- #endif
- mid_platform_reboot(mid_info);
- }
- if (reloadmaxwaittime) {
- maxwaittime = reloadmaxwaittime;
- reloadmaxwaittime = 0;
- }
- else {
- MLGE("STMACH: MID is NOW out of sync. MID is in STATE_OFF BUT modem is in Zombie state.");
- MLGE("GPIO: GPIO_ID_RESOUT2 STATUS :%d", mid_gpio_get_value(mid_info->gpios, GPIO_ID_RESOUT2));
- MLGE("GPIO: GPIO_ID_PWRRSTIN STATUS :%d", mid_gpio_get_value(mid_info->gpios, GPIO_ID_PWRRSTIN));
- /* Unrecoverable case: This will trig a platform reboot or a MID spin loop. */
- #if defined(MOTOROLA_FEATURE)
- mid_statemachine_log_panic_apr("Subtype: MID is NOW out of sync. MID is in STATE_OFF BUT modem is in Zombie state after shutdown timeout.\n", mid_info->config->critical_panic_detection_file);
- #endif
- mid_platform_reboot(mid_info);
- }
- }
- else {
- MLGE("STMACH: MID is NOW out of sync. MID is in STATE_OFF BUT modem is in Zombie state.");
- MLGE("GPIO: GPIO_ID_RESOUT2 STATUS :%d", mid_gpio_get_value(mid_info->gpios, GPIO_ID_RESOUT2));
- MLGE("GPIO: GPIO_ID_PWRRSTIN STATUS :%d", mid_gpio_get_value(mid_info->gpios, GPIO_ID_PWRRSTIN));
- if (!mid_info->shutdown_retry_left) {
- /* Unrecoverable case: This will trig a platform reboot or a MID spin loop. */
- #if defined(MOTOROLA_FEATURE)
- mid_statemachine_log_panic_apr("Subtype: MID is NOW out of sync. MID is in STATE_OFF BUT modem is in Zombie state after shutdown timeout.\n", mid_info->config->critical_panic_detection_file);
- #endif
- mid_platform_reboot(mid_info);
- } else {
- /* On rare occasions this can be recoverable... */
- mid_info->shutdown_retry_left--;
- return;
- }
- }
- }
- }
- /* OSMIUM special case, deassert GPIO_ID_RESET if used. */
- if (mid_info->config->modem_arch_id == OSMIUM && mid_gpio_used(mid_info->gpios, GPIO_ID_RESET) && mid_gpio_get_value(mid_info->gpios, GPIO_ID_RESET))
- mid_gpio_deassert(mid_info->gpios, GPIO_ID_RESET);
- MLGD("STMACH: Modem is now off.");
- if (mid_info->ipc_reboot_received) {
- mid_info->ipc_reboot_received = 0;
- #if defined(MOTOROLA_FEATURE)
- mid_statemachine_log_panic_apr("Subtype: Modem IPC failure, no system reboot.\n", mid_info->config->silent_panic_detection_file);
- #endif
- }
- ipc_prepare_message(&msg, STATECHANGE, "off", get_reason_from_last_event(mid_info));
- ipc_send_message(msg);
- mid_info->state = STATE_OFF;
- mid_info->shutdown_retry_left = mid_info->config->shutdown_retry;
- }
- static int modem_power_on(struct mid* mid_info, int disable_io_safe_mode)
- {
- int res = 0;
- MLGD("STMACH: MID execute power on sequence");
- #if !defined(MOTOROLA_FEATURE)
- if (disable_io_safe_mode)
- #endif
- mid_disable_io_safe_mode(mid_info);
- MLGD("GPIO: Assert PWRRSTOUT pin");
- if (unlikely(mid_gpio_assert(mid_info->gpios, GPIO_ID_PWRRSTOUT))) {
- MLGE("GPIO: Can't assert GPIO_PWRRSTOUT");
- mid_enable_io_safe_mode(mid_info);
- return -EMIDGPIO;
- }
- usleep(2000);
- if (mid_info->config->use_on_sw_c) {
- /* OnSwC */
- MLGD("GPIO: Using OnSwC");
- MLGD("GPIO: Assert MOD ON pin");
- res = mid_gpio_assert(mid_info->gpios, GPIO_ID_ON);
- if (unlikely(res)) {
- MLGE("GPIO: Can't assert GPIO_ON");
- mid_enable_io_safe_mode(mid_info);
- return -EMIDGPIO;
- }
- if (!mid_gpio_used(mid_info->gpios, GPIO_ID_PWRRSTIN))
- mid_info->modem_is_on = 1;
- return 0;
- }
- /* OnSwA */
- MLGD("GPIO: Using OnSwA");
- MLGD("GPIO: Assert MOD ON pin");
- res = mid_gpio_assert(mid_info->gpios, GPIO_ID_ON);
- if (unlikely(res)) {
- MLGE("GPIO: Can't assert GPIO_ON");
- mid_enable_io_safe_mode(mid_info);
- return -EMIDGPIO;
- }
- mid_info->power_on_release = 1;
- if ((!isdirempty(mid_info->config->initial_rdir) && (!mid_info->config->initial_enable_bootldr)) || !mid_gpio_used(mid_info->gpios, GPIO_ID_RESOUT2)) {
- /* This is for:
- * - non RESOUT2 enabled hardware
- * - flashed configuration when modem has to be flashed - No RESOUT2 are available from loaders */
- MLGD("GPIO: OnSwa long assert: %d seconds.", MODEM_POWER_ON_LAT);
- sleep(MODEM_POWER_ON_LAT);
- MLGD("GPIO: De-assert MOD ON pin");
- res = mid_gpio_deassert(mid_info->gpios, GPIO_ID_ON);
- if (unlikely(res)) {
- MLGE("GPIO: Can't deassert GPIO_ON");
- mid_info->power_on_release = 0;
- mid_enable_io_safe_mode(mid_info);
- return -EMIDGPIO;
- }
- mid_info->power_on_release = 0;
- }
- if (!mid_gpio_used(mid_info->gpios, GPIO_ID_PWRRSTIN))
- mid_info->modem_is_on = 1;
- return 0;
- }
- // Helper thread procedures
- struct delayed_dump_args {
- struct mid* mid_info;
- unsigned int seconds;
- };
- static void *delayed_dump(apr_thread_t* thread, void *arg)
- {
- UNUSED(thread);
- struct delayed_dump_args* args=arg;
- MLGD("STMACH: MID execute delayed dump sequence, with %d seconds delay", args->seconds);
- sleep(args->seconds);
- SET_FLAG(args->mid_info->event, MID_GPIO_RST2_EVT);
- MLGD("STMACH: MID_GPIO_RST2_EVT event set.");
- free(args);
- return NULL;
- }
- static int start_delayed_dump(apr_thread_t** thread, struct mid* mid_info, unsigned int seconds)
- {
- struct delayed_dump_args* args=malloc(sizeof(struct delayed_dump_args));
- args->mid_info=mid_info;
- args->seconds=seconds;
- return apr_thread_create(thread, NULL, delayed_dump, args, mid_info->pool);
- }
- static void *rfm_sleep(apr_thread_t* thread, void *arg)
- {
- UNUSED(thread);
- struct mid* mid_info=arg;
- int timetosleep = mid_info->config->rfm_delay;
- UNUSED(arg);
- MLGD("STMACH: SIMULATED MID_CFRDY_EVT (with a sleep command with sleep delay: %d) \n", timetosleep);
- if (mid_info->config->initial_sec_data_conf == 1) {
- /* Sanity delay to let enough time for a non prepared hardware */
- timetosleep = 10;
- }
- sleep(timetosleep);
- if (mid_info->config->enable_at_channel) {
- if (mid_at_chnl_open(mid_info)) {
- MLGE("MID: Unable to open AT channel. Modem will be shutdown.");
- shutdown_modem(mid_info);
- return 0;
- }
- /* Response for oppening the AT channel will generated the CFRDY event */
- return 0;
- }
- /* Since we don't open the AT channel we must generate the CFRDY event here */
- SET_FLAG(mid_info->event, MID_CFRDY_EVT);
- MLGD("STMACH: MID_CFRDY_EVT event set.");
- return 0;
- }
- /***************
- ANY
- ***************/
- MID_Event_Oper_t MID_State_Any__Event_GPIO_PRST_EVT(struct mid *mid_info)
- {
- union ipc_msg msg;
- MLGD("STMACH: MID execute Action: GPIO_PRST_EVT processing.");
- if (mid_gpio_get_value(mid_info->gpios, GPIO_ID_PWRRSTIN)) {
- MLGW("STMACH: Modem GPIO PWRRSTIN event, and GPIO level is high. This means modem is powered.");
- return MID_CLEAR_EVENT;
- }
- MLGW("STMACH: Modem unexpected powered off according GPIO PWRRSTIN.");
- (void)my_system(mid_info, mid_info->config->mod_off_cmd);
- ipc_prepare_message(&msg, STATECHANGE, "off", get_reason_from_last_event(mid_info));
- ipc_send_message(msg);
- mid_info->state = STATE_OFF;
- return MID_CLEAR_EVENT;
- }
- MID_Event_Oper_t MID_State_Any__Event_HIGH_TEMPERATURE_EVT(struct mid *mid_info)
- {
- MLGD("STMACH: MID execute Action: HIGH_TEMPERATURE_EVT processing.");
- shutdown_modem(mid_info);
- return MID_CLEAR_EVENT;
- }
- MID_Event_Oper_t MID_State_Any__Event_LOW_BATTERY_EVT(struct mid *mid_info)
- {
- MLGD("STMACH: MID execute Action: LOW_BATTERY_EVT processing.");
- shutdown_modem(mid_info);
- return MID_CLEAR_EVENT;
- }
- MID_Event_Oper_t UnExpected_Event(struct mid *mid_info)
- {
- MLGE("STMACH: MID received event:%s in state:%s. This event will not be handled and cleared because it s a out of sync event.", MID_EventNames[mid_info->cur_event],MID_StateNames[mid_info->state]);
- return MID_CLEAR_EVENT;
- }
- MID_Event_Oper_t Save_Event(struct mid *mid_info_p)
- {
- UNUSED(mid_info_p);
- return MID_KEEP_EVENT;
- }
- MID_Event_Oper_t MID_State_Any__Event_SIG_KILL(struct mid *mid_info)
- {
- MLGD("STMACH: MID execute Action: SIG_KILL processing.");
- shutdown_modem(mid_info);
- return MID_KEEP_EVENT;
- }
- MID_Event_Oper_t UnExpected_Async_Event(struct mid *mid_info)
- {
- MLGE("STMACH: MID received event:%s in state:%s. This event will not be handled and cleared because it s a out of sync event.", MID_EventNames[mid_info->cur_event],MID_StateNames[mid_info->state]);
- return MID_CLEAR_EVENT;
- }
- MID_Event_Oper_t MID_State_Any__Event_FW_XFER_OPS(struct mid *mid_info)
- {
- const char * errorstr = NULL;
- MLGD("STMACH: MID execute Action: FW_XFER_OPS_EVT processing.");
- MLGD("STMACH: MID_State_Any__Event_FW_XFER_OPS - result is %d", mid_info->fw_xfer_result);
- /* Handler for fw xfer thread status event */
- if (mid_info->fw_xfer_result == MID_FW_XFER_OK) {
- MLGD("MID: MID_State_Any__Event_FW_XFER_OPS: Got OK"); //DBG
- if (ipc_send_async_reply(&mid_info->fw_upgr_img_xfer_reply_msg, "OK")) {
- MLGE("DBUS: MID_State_Any__Event_FW_XFER_OPS: Failed to send reply");
- }
- } else {
- MLGD("MID: MID_State_Any__Event_FW_XFER_OPS: Got ERROR"); //DBG
- errorstr = mid_fw_upgrade_get_error_str(mid_info, mid_info->fw_upgr_last_error);
- if (ipc_send_async_reply(&mid_info->fw_upgr_img_xfer_reply_msg,
- (errorstr ? errorstr : "ERROR"))) {
- MLGE("DBUS: MID_State_Any__Event_FW_XFER_OPS: Failed to send reply");
- }
- }
- return MID_CLEAR_EVENT;
- }
- MID_Event_Oper_t MID_State_Any__Event_FW_UPGR(struct mid *mid_info)
- {
- const char * error = NULL;
- MLGD("STMACH: MID execute Action: FW_UPGR_EVT processing.");
- switch (mid_info->cur_event) {
- case MID_IPC_FW_UPGR_IMG_XFER_EVT:
- if (mid_info->fw_upgr_img_xfer_reply_msg != NULL) {
- error = mid_fw_upgrade_get_error_str(mid_info, MID_FW_UPGR_RSLT_REJECTED);
- if (ipc_send_async_reply(&mid_info->fw_upgr_img_xfer_reply_msg,
- (error ? error : "REJECTED"))) {
- MLGE("DBUS: UnExpected_Async_Event: Failed to send reply");
- }
- }
- break;
- case MID_IPC_FW_UPGR_FLASH_EVT:
- if (mid_info->fw_upgr_flash_reply_msg != NULL) {
- error = mid_fw_upgrade_get_error_str(mid_info, MID_FW_UPGR_RSLT_REJECTED);
- if (ipc_send_async_reply(&mid_info->fw_upgr_flash_reply_msg,
- (error ? error : "REJECTED"))) {
- MLGE("DBUS: UnExpected_Async_Event: Failed to send reply");
- }
- }
- break;
- case MID_IPC_FW_UPGR_STATUS_EVT:
- if (mid_info->fw_upgr_status_reply_msg != NULL) {
- error = mid_fw_upgrade_get_error_str(mid_info, MID_FW_UPGR_RSLT_REJECTED);
- if (ipc_send_async_reply(&mid_info->fw_upgr_status_reply_msg,
- (error ? error : "REJECTED"))) {
- MLGE("DBUS: UnExpected_Async_Event: Failed to send reply");
- }
- }
- break;
- case MID_IPC_RBT_EVT: /* Fall though */
- case MID_GPIO_RST2_EVT: /* Fall though */
- case MID_GPIO_PRST_EVT: /* Fall though */
- case MID_MODEM_HALT_EVT: /* Fall though */
- case MID_MODEM_START_EVT: /* Fall though */
- case MID_SIG_KILL_EVT: /* Fall though */
- case MID_LONG_OPS_EVT: /* Fall though */
- case MID_CFRDY_EVT: /* Fall though */
- case MID_HIGH_TEMPERATURE_EVT: /* Fall though */
- case MID_LOW_BATTERY_EVT: /* Fall though */
- case MID_AT_CFUN0_EVT: /* Fall though */
- case MID_AT_CFUN100_EVT: /* Fall though */
- case MID_FW_XFER_OPS_EVT: /* Fall though */
- case MID_FW_XFER_PROGRESS_EVT: /* Fall though */
- case MID_TIMEOUT_EVT: /* Fall though */
- case MID_FLASH_START_EVT: /* Fall though */
- case MID_FLASH_END_EVT: /* Fall though */
- case MID_LAST_EVT: /* Fall though */
- default:
- MLGE("STMACH: Current event(%s) doesn't match any firmware upgrade event!",MID_EventNames[mid_info->cur_event]);
- break;
- }
- return MID_CLEAR_EVENT;
- }
- MID_Event_Oper_t MID_State_Any__Event_TIMEOUT(struct mid *mid_info)
- {
- MLGD("STMACH: MID execute Action: TIMEOUT_EVT processing.");
- MLGW("STMACH: Shutting down modem due to timeout in a transient state");
- /* If none of the two events below is set we need to set these in */
- /* order to reboot after shutting down modem */
- if (!FLAG_UP(mid_info->event, MID_MODEM_START_EVT) && !FLAG_UP(mid_info->event, MID_IPC_RBT_EVT)) {
- SET_FLAG(mid_info->event, MID_MODEM_START_EVT);
- MLGD("STMACH: MID_MODEM_START_EVT event set.");
- }
- /* Special care when we are in ModInfUp state and when we don t receive EMRDY from modem. AT channel could be non-responsive
- * So AT is closed here to prevent shutdown hanging */
- if (mid_info->state == STATE_MODINF_UP)
- mid_at_chnl_close(mid_info);
- shutdown_modem(mid_info);
- return MID_CLEAR_EVENT;
- }
- /***************
- FLASHING
- ***************/
- static MID_Event_Oper_t MID_State_Flashing__Event_GPIO_PRST(struct mid *mid_info)
- {
- if (mid_gpio_get_value(mid_info->gpios, GPIO_ID_PWRRSTIN) == 0) {
- MLGD("Ingnoring PWRRSTIN going low during flashing");
- return MID_CLEAR_EVENT;
- }
- mid_disable_tx_safe_mode(mid_info);
- mid_mfa_notify_on(mid_info->mfa);
- return MID_CLEAR_EVENT;
- }
- static MID_Event_Oper_t MID_State_Flashing__Event_FLASH_START(struct mid *mid_info)
- {
- if (modem_power_on(mid_info, 1) != 0) {
- MLGE("MFA: Failed to power up the modem");
- mid_mfa_stop(mid_info->mfa, false);
- SET_FLAG(mid_info->event, MID_FLASH_END_EVT);
- }
- return MID_CLEAR_EVENT;
- }
- static MID_Event_Oper_t mid_statemachine_try_boot(struct mid *mid_info)
- {
- union ipc_msg msg;
- #if defined(MOTOROLA_FEATURE)
- if (mot_mid_info.dual_boot_mode)
- mid_info->boot_retry_left = mid_info->config->boot_retry;
- #endif
- /* FLASHED VARIANT - POWER UP MODEM */
- MLGD("MID: MID power up the modem started (Retries left:%d)",mid_info->boot_retry_left);
- if (mid_info->boot_retry_left == 0 && !mid_info->boot_failed) {
- if (mid_info->config->reboot_on_failure)
- #if defined(MOTOROLA_FEATURE)
- {
- mid_statemachine_log_panic_apr("Subtype: MID bootloader: maximum number of retries reached.\n", mid_info->config->critical_panic_detection_file);
- #endif
- mid_platform_reboot(mid_info);
- #if defined(MOTOROLA_FEATURE)
- }
- #endif
- MLGD("MID: Maximum(%d) number of retries reached", mid_info->config->boot_retry);
- MLGD("STMACH: MID will stay in STATE_OFF.");
- mid_info->boot_retry_left = mid_info->config->boot_retry;
- mid_info->boot_failed = 1;
- return MID_CLEAR_EVENT;
- } else if (mid_info->boot_retry_left > 0) {
- mid_info->boot_failed = 0;
- }
- mid_info->boot_retry_left--;
- #ifdef PERF_MEASUREMENT
- if (clock_gettime(CLOCK_MONOTONIC, &mid_info->modemImagesStarted))
- MLGW("TIME: Error getting monotonic clock. Following time report information should be considered as wrong.");
- if (clock_gettime(CLOCK_MONOTONIC, &mid_info->modemImagesFinished))
- MLGW("TIME: Error getting monotonic clock. Following time report information should be considered as wrong.");
- #endif
- if (modem_power_on(mid_info, 0)) {
- MLGE("GPIO: MID modem power on failure");
- return MID_KEEP_EVENT;
- }
- if (!mid_gpio_used(mid_info->gpios, GPIO_ID_RESOUT2) || (!mid_gpio_is_ctrl_enabled(mid_info->gpios))) {
- /* Flashed variant witout gpio RST2 ctrl - e.g. PC start everything here */
- if (my_system(mid_info, mid_info->config->mod_ifup_cmd) != 0) {
- /* We always check for a modem dump in shutdown_modem */
- /* unlesss we tried retrieveing a dump before we call shutdown */
- shutdown_modem(mid_info);
- return MID_KEEP_EVENT;
- }
- if (mid_info->config->enable_at_channel && mid_at_chnl_open(mid_info)) {
- MLGE("AT: Unable to open AT channel. MID will shutdown the modem.");
- /* We always check for a modem dump in shutdown_modem */
- /* unlesss we tried retrieveing a dump before we call shutdown */
- shutdown_modem(mid_info);
- return MID_KEEP_EVENT;
- }
- /* And we bypass STATE_BOOT as RESOUT2 will never come */
- if (mid_info->config->enable_at_channel)
- /* AT channel enabled, we wait for EMRDY */
- mid_info->state = STATE_MODINF_UP;
- else {
- int res = my_system(mid_info, mid_info->config->mod_on_cmd);
- if (res != 0) {
- /* We always check for a modem dump in shutdown_modem */
- /* unlesss we tried retrieveing a dump before we call shutdown */
- shutdown_modem(mid_info);
- return MID_KEEP_EVENT;
- }
- /* Go in ON - clear START_EVT and RBT_EVT */
- CLEAR_FLAG(mid_info->event, MID_MODEM_START_EVT);
- CLEAR_FLAG(mid_info->event, MID_IPC_RBT_EVT);
- mid_info->state = STATE_ON;
- ipc_prepare_message(&msg, STATECHANGE, "on", get_reason_from_last_event(mid_info));
- ipc_send_message(msg);
- mid_mfa_notify_on(mid_info->mfa);
- }
- return MID_KEEP_EVENT;
- }
- mid_info->state = STATE_BOOT;
- ipc_prepare_message(&msg, STATECHANGE, "booting", get_reason_from_last_event(mid_info));
- ipc_send_message(msg);
- return MID_KEEP_EVENT;
- }
- static bool mid_statemachine_start_flashing(struct mid* mid_info)
- {
- MLGD("MID: %s is not empty. MID flash service started(Retries left:%d)", mid_info->config->initial_rdir, mid_info->flash_retry_left);
- if (mid_info->flash_retry_left == 0 && !mid_info->flash_failed) {
- MLGD("MID: Maximum(%d) number of retries reached, trying to boot modem anyway", mid_info->config->flash_retry);
- mid_info->flash_retry_left = mid_info->config->flash_retry;
- mid_info->flash_failed = true;
- /* The flashing failed n times, lets atleast try to boot modem */
- return false;
- } else if (mid_info->flash_retry_left > 0) {
- mid_info->flash_failed = false;
- }
- mid_info->flash_retry_left--;
- #ifdef PERF_MEASUREMENT
- if (clock_gettime(CLOCK_MONOTONIC, &mid_info->modemImagesStarted))
- MLGW("TIME: Error getting monotonic clock. Following time report information should be considered as wrong.");
- #endif
- mid_disable_gpio_service_safe_mode(mid_info);
- mid_enable_tx_safe_mode(mid_info);
- if (unlikely(mid_gpio_assert(mid_info->gpios, GPIO_ID_SERVICE))) {
- MLGE("GPIO: Can't assert GPIO_MOD_SERVICE");
- mid_enable_gpio_service_safe_mode(mid_info);
- return false;
- }
- if (my_system(mid_info, mid_info->config->mod_prefl_cmd) != 0) {
- if (unlikely(mid_gpio_deassert(mid_info->gpios, GPIO_ID_SERVICE)))
- MLGE("GPIO: Can't deassert GPIO_MOD_SERVICE");
- mid_enable_gpio_service_safe_mode(mid_info);
- /* Ignoring return values when cleaning up */
- (void)my_system(mid_info, mid_info->config->mod_postfl_cmd);
- return false;
- }
- if (mid_mfa_start(mid_info->mfa)) {
- MLGD("MFA started");
- } else {
- MLGE("MID: No dir cleanup will be performed - flash sequence will be again triggered");
- if (unlikely(mid_gpio_deassert(mid_info->gpios, GPIO_ID_SERVICE)))
- MLGE("GPIO: Can't deassert GPIO_MOD_SERVICE");
- mid_enable_gpio_service_safe_mode(mid_info);
- (void)my_system(mid_info, mid_info->config->mod_postfl_cmd);
- shutdown_modem(mid_info);
- return false;
- }
- return true;
- }
- static MID_Event_Oper_t MID_State_Flashing__Event_FLASH_END(struct mid *mid_info)
- {
- MLGD("MID: Modem flash ended.");
- if (!mid_mfa_was_successful(mid_info->mfa)) {
- MLGW("STMACH: MFA Flashing failed. Retrying");
- if (modem_power_off(mid_info) != 0) {
- MLGE("MFA: MID modem power off failure");
- }
- #ifdef MOTOROLA_FEATURE
- if (mot_mid_info.recovery_mode) {
- /* Broadcast status if MID was not terminated externally */
- if (!(mid_info->event & 1<<MID_SIG_KILL_EVT)) {
- union ipc_msg msg;
- ipc_prepare_message(&msg, MFARESULT, "fail");
- ipc_send_message(msg);
- }
- /* Exit to recovery executables to potentially retry flashing */
- MLGE("Flash fail: Exiting MID in recovery mode.");
- exit(EXIT_FAILURE);
- }
- #endif /* MOTOROLA_FEATURE */
- if (!mid_statemachine_start_flashing(mid_info)) {
- MLGE("MFA: Failed to start flashing");
- }
- // If we've given up flashing, we just continue with normal bootup.
- if (!mid_info->flash_failed) {
- return MID_CLEAR_EVENT;
- }
- }
- if(purgedir(mid_info->config->initial_rdir))
- MLGE("MID: Failed to purge dir: %s. Continue anyway", mid_info->config->initial_rdir);
- #ifdef MOTOROLA_FEATURE
- if (!mot_mid_info.recovery_mode)
- {
- #endif
- /* Since the modem images files is deleted we keep the event */
- /* so the modem will be tried to boot(without flashing) in */
- /* the next iteration */
- if (my_system(mid_info, mid_info->config->mod_postfl_cmd) != 0)
- return MID_KEEP_EVENT;
- #ifdef MOTOROLA_FEATURE
- }
- else
- {
- /* MID was launched in recovery mode: shutdown modem */
- my_system(mid_info, mid_info->config->mod_postfl_cmd);
- shutdown_modem(mid_info);
- /* Broadcast status if MID was not terminated externally */
- if (!(mid_info->event & 1<<MID_SIG_KILL_EVT)) {
- union ipc_msg msg;
- ipc_prepare_message(&msg, MFARESULT, "pass");
- ipc_send_message(msg);
- }
- /* Exit to recovery executables to reboot to normal mode. */
- MLGE("Flash success: Exiting MID in recovery mode.");
- exit(EXIT_SUCCESS);
- }
- #endif /* MOTOROLA_FEATURE */
- /* Since flashing went well we just continue even if this failed */
- /* Modem is turned off by MFA. This may not be correct */
- if (unlikely(mid_gpio_deassert(mid_info->gpios, GPIO_ID_SERVICE)))
- MLGE("GPIO: Can't deassert GPIO_MOD_SERVICE");
- if (unlikely(mid_gpio_deassert(mid_info->gpios, GPIO_ID_PWRRSTOUT)))
- MLGE("GPIO: Can't deassert GPIO_PWRRSTOUT");
- /* Set all interface in safe mode */
- mid_enable_gpio_service_safe_mode(mid_info);
- mid_enable_io_safe_mode(mid_info);
- /* Sanity sleep to let time for HW */
- MLGD("STMACH: MID will be idle for 50 millisecond to allow safe mode propagation on IOs.");
- usleep(50000);
- /* Check if modem is down - otherwise power it off */
- if (mid_gpio_get_value(mid_info->gpios, GPIO_ID_RESOUT2) || mid_gpio_get_value(mid_info->gpios, GPIO_ID_PWRRSTIN)
- || mid_info->config->flash_force_pwroff) {
- if (mid_info->config->flash_force_pwroff)
- /* For modem that does not automaticaly power off, we can force it */
- MLGD("STMACH: Option flash_force_pwroff is set. Modem power_off function is called now.");
- else
- MLGD("STMACH: Modem is ON according RESOUT2 and / or PWRRSTIN level. Modem power_off function is called now.");
- shutdown_modem(mid_info);
- }
- return mid_statemachine_try_boot(mid_info);
- }
- /***************
- OFF
- ***************/
- MID_Event_Oper_t MID_State_Off__Event_SIG_KILL(struct mid *mid_info)
- {
- MLGD("STMACH: MID execute Action: SIG_KILL_EVT processing.");
- state_all_evt_sig_kill(mid_info);
- return MID_KEEP_EVENT;
- }
- /* Only used in the function below. We cannot use stack variable when creating thread. */
- /* The stack is changed before the thread use the variable */
- static int _timeout;
- MID_Event_Oper_t MID_State_Off__Event_MODEM_START__IPC_RBT(struct mid *mid_info)
- {
- int res;
- apr_status_t status;
- MLGD("STMACH: MID execute Action: START / IPC_RBT_EVT processing.");
- if (FLAG_UP(mid_info->event, MID_MODEM_HALT_EVT)) {
- CLEAR_FLAG(mid_info->event, MID_MODEM_HALT_EVT);
- MLGD("STMACH: MID_MODEM_HALT_EVT event cleared.");
- return MID_CLEAR_EVENT;
- }
- mid_info->kill_threads = 0;
- /* Since the current setup doesn't always support RSTIN we need to keep modem on state */
- if (!mid_gpio_used(mid_info->gpios, GPIO_ID_PWRRSTIN))
- mid_info->modem_is_on = 0;
- #ifdef PERF_MEASUREMENT
- if (clock_gettime(CLOCK_MONOTONIC, &mid_info->modemBootStarted))
- MLGW("TIME: Error getting monotonic clock. Following time report information should be considered as wrong.");
- #endif
- /* TODO: Consider remove this when crashdump is tested and working */
- if (mid_info->config->crashdump_dev_mode == -1) {
- res = start_delayed_dump(&mid_info->mid_crashdump_td, mid_info, _timeout);
- if (res) {
- MLGE("MID: MID delayed crashdump thread creation failure: %s", strerror(res));
- }
- mid_info->flash_retry_left = mid_info->config->flash_retry;
- mid_info->boot_retry_left = mid_info->config->boot_retry;
- mid_info->boot_failed = 0;
- mid_info->flash_failed = 0;
- mid_info->state = STATE_ON;
- return MID_CLEAR_EVENT;
- }
- /* Need to handle runtime mode SERVICE specificaly */
- if (strncmp("service",mid_info->config->runtime_mode,strlen("service")) == 0) {
- mid_disable_gpio_service_safe_mode(mid_info);
- if (unlikely(mid_gpio_assert(mid_info->gpios, GPIO_ID_SERVICE))) {
- MLGE("GPIO: Can't assert GPIO_MOD_SERVICE");
- mid_enable_gpio_service_safe_mode(mid_info);
- return MID_CLEAR_EVENT;
- }
- if (my_system(mid_info, mid_info->config->mod_prefl_cmd) != 0) {
- /* Ignoring return values when cleaning up */
- (void)mid_gpio_deassert(mid_info->gpios, GPIO_ID_SERVICE);
- mid_enable_gpio_service_safe_mode(mid_info);
- (void)my_system(mid_info, mid_info->config->mod_postfl_cmd);
- return MID_CLEAR_EVENT;
- }
- #if defined(MOTOROLA_FEATURE)
- (void)my_system(mid_info, mot_mid_info.svc_mode_cmd);
- #endif
- if (modem_power_on(mid_info, 0) != 0) {
- MLGE("GPIO: Unable to power on modem!");
- /* Ignoring return values when cleaning up */
- (void)mid_gpio_deassert(mid_info->gpios, GPIO_ID_SERVICE);
- mid_enable_gpio_service_safe_mode(mid_info);
- (void)my_system(mid_info, mid_info->config->mod_postfl_cmd);
- return MID_CLEAR_EVENT;
- }
- MLGD("MID: Entered service mode, update mid.conf and restart host "
- "in order to exit service mode");
- return MID_CLEAR_EVENT;
- }
- /* FLASH OPERATION TRIGGER */
- MLGD("isdirempty(\"%s\")==%d", mid_info->config->initial_rdir, isdirempty(mid_info->config->initial_rdir));
- MLGD("initial_enable_bootldr==%d", mid_info->config->initial_enable_bootldr);
- MLGD("flash_failed=%d", mid_info->flash_failed);
- if (!isdirempty(mid_info->config->initial_rdir) && (!mid_info->config->initial_enable_bootldr) && !mid_info->flash_failed) {
- union ipc_msg msg;
- if (!mid_statemachine_start_flashing(mid_info))
- return MID_KEEP_EVENT;
- MLGD("Entering FLASHING state");
- mid_info->state = STATE_FLASHING;
- ipc_prepare_message(&msg, STATECHANGE, "flashing", get_reason_from_last_event(mid_info));
- ipc_send_message(msg);
- return MID_CLEAR_EVENT;
- }
- if (mid_info->config->initial_enable_bootldr) {
- /* FLASHLESS VARIANT - FIRMWARE UPLOAD */
- MLGD("MID: MID bootloader started(Retries left:%d)",mid_info->boot_retry_left);
- if (mid_info->boot_retry_left == 0 && !mid_info->boot_failed) {
- mid_info->boot_retry_left = mid_info->config->boot_retry;
- mid_info->boot_failed = 1;
- if (mid_info->config->reboot_on_failure) {
- #if defined(MOTOROLA_FEATURE)
- mid_statemachine_log_panic_apr("Subtype: MID bootloader: maximum number of retries reached.\n", mid_info->config->critical_panic_detection_file);
- #endif
- mid_platform_reboot(mid_info);
- }
- MLGD("MID: Maximum(%d) number of retries reached", mid_info->config->boot_retry);
- MLGD("STMACH: MID will stay in STATE_OFF.");
- return MID_CLEAR_EVENT;
- } else if (mid_info->boot_retry_left > 0) {
- mid_info->boot_failed = 0;
- }
- mid_info->boot_retry_left--;
- if (my_system(mid_info, mid_info->config->mod_prefl_cmd) != 0)
- return MID_KEEP_EVENT;
- mid_info->long_ops_result = MID_FLBOOT_OK;
- #ifdef PERF_MEASUREMENT
- if (clock_gettime(CLOCK_MONOTONIC, &mid_info->modemImagesStarted))
- MLGW("TIME: Error getting monotonic clock. Following time report information should be considered as wrong.");
- #endif
- if (mid_configure_dev(mid_info->config->prim_dev_config, mid_info->config->prim_dev_config->devtype) != 0) {
- MLGE("MID: Error on primary device configuration");
- return MID_KEEP_EVENT;
- }
- if (mid_info->config->link_switch && (mid_configure_dev(mid_info->config->sec_dev_config,
- mid_info->config->sec_dev_config->devtype) != 0)) {
- MLGE("MID: Error on secondary device configuration");
- return MID_KEEP_EVENT;
- }
- if ((status = apr_thread_create(&mid_info->mid_flboot_td, NULL, mid_info->moli_boot, mid_info, mid_info->pool)) != APR_SUCCESS) {
- char message[100];
- MLGE("MID: MID moli_boot thread creation failure: %s",
- apr_strerror(status, message, sizeof(message)));
- (void)my_system(mid_info, mid_info->config->mod_postfl_cmd);
- shutdown_modem(mid_info);
- return MID_KEEP_EVENT;
- }
- mid_info->state = STATE_BOOT;
- return MID_KEEP_EVENT;
- }
- return mid_statemachine_try_boot(mid_info);
- }
- /***************
- BOOT
- ***************/
- MID_Event_Oper_t MID_State_Boot__Event_LONG_OPS(struct mid *mid_info)
- {
- int res;
- union ipc_msg msg;
- MLGD("STMACH: MID execute Action: LONG_OPS_EVT processing. Firmware upload is completed.");
- #ifdef PERF_MEASUREMENT
- if (clock_gettime(CLOCK_MONOTONIC, &mid_info->modemImagesFinished))
- MLGW("TIME: Error getting monotonic clock. Following time report information should be considered as wrong.");
- #endif
- if (mid_info->long_ops_result != MID_FLBOOT_OK) {
- MLGE("MID: MID Failure on firmware upload. Try to boot again");
- (void)my_system(mid_info, mid_info->config->mod_postfl_cmd);
- shutdown_modem(mid_info);
- return MID_CLEAR_EVENT;
- }
- /* Flashless variant without gpio RST2 ctrl assume modem is ready and start RFM */
- /* With RST2 support we just stay in current state and wait for the RST2 event */
- MLGD("MID: MID Firmware upload completed");
- if (!mid_gpio_used(mid_info->gpios, GPIO_ID_RESOUT2)) {
- if (!mid_info->config->use_on_sw_c) {
- /* OnSwA - deassert power ON */
- if (mid_gpio_deassert(mid_info->gpios, GPIO_ID_ON))
- MLGE("GPIO: Can't deassert GPIO_ON");
- }
- res = my_system(mid_info, mid_info->config->mod_postfl_cmd);
- if (res != 0)
- return MID_CLEAR_EVENT;
- res = my_system(mid_info, mid_info->config->mod_ifup_cmd);
- if (res != 0) {
- shutdown_modem(mid_info);
- return MID_CLEAR_EVENT;
- }
- /* RFM will be started when receiving the booting ipc event */
- ipc_prepare_message(&msg, STATECHANGE, "booting", get_reason_from_last_event(mid_info));
- ipc_send_message(msg);
- if (mid_info->config->rfm_delay) {
- apr_status_t status;
- status = apr_thread_create(&mid_info->mid_rfmsleep_td, NULL, &rfm_sleep, mid_info, mid_info->pool);
- if (status != APR_SUCCESS) {
- char message[100];
- MLGE("MID: MID rfm_sleep thread creation failure: %s",
- apr_strerror(status, message, sizeof(message)));
- shutdown_modem(mid_info);
- return MID_CLEAR_EVENT;
- }
- mid_info->state = STATE_MODINF_UP;
- return MID_CLEAR_EVENT;
- }
- if (mid_info->config->enable_at_channel) {
- if (mid_at_chnl_open(mid_info)) {
- MLGE("AT: Unable to open AT channel. MID will shutdown the modem.");
- shutdown_modem(mid_info);
- return MID_CLEAR_EVENT;
- }
- mid_info->state = STATE_MODINF_UP;
- return MID_CLEAR_EVENT;
- }
- /* We just set the MID_CFRDY_EVT event and enter the MODINF_UP state so */
- /* so we can handle the code at the same place */
- SET_FLAG(mid_info->event, MID_CFRDY_EVT);
- MLGD("STMACH: MID_CFRDY_EVT event set.");
- mid_info->state = STATE_MODINF_UP;
- return MID_CLEAR_EVENT;
- }
- return MID_CLEAR_EVENT;
- }
- MID_Event_Oper_t MID_State_Boot__Event_GPIO_RST2(struct mid *mid_info)
- {
- int res;
- union ipc_msg msg;
- MLGD("STMACH: MID execute Action: GPIO_RST2_EVT processing.");
- if (mid_info->power_on_release) {
- /* OnSwA specific */
- MLGD("GPIO: De-assert MOD ON pin");
- res = mid_gpio_deassert(mid_info->gpios, GPIO_ID_ON);
- if (unlikely(res)) {
- MLGE("GPIO: Can't deassert GPIO_ON");
- mid_info->power_on_release = 0;
- }
- mid_info->power_on_release = 0;
- }
- #ifdef PERF_MEASUREMENT
- if (clock_gettime(CLOCK_MONOTONIC, &mid_info->modemRST2))
- MLGW("TIME: Error getting monotonic clock. Following time report information should be considered as wrong.");
- #endif
- if (!mid_gpio_get_value(mid_info->gpios, GPIO_ID_RESOUT2)) {
- return MID_CLEAR_EVENT;
- }
- /* We only do this for flashless, for the flashed variant we don't execute prefl_ and postfl_cmd */
- if (mid_info->config->initial_enable_bootldr) {
- res = my_system(mid_info, mid_info->config->mod_postfl_cmd);
- if (res != 0) {
- goto error_exit_shutdown;
- }
- }
- res = my_system(mid_info, mid_info->config->mod_ifup_cmd);
- if (res != 0) {
- goto error_exit_shutdown;
- }
- /* RFM will be started when receiving the booting ipc event */
- ipc_prepare_message(&msg, STATECHANGE, "booting", get_reason_from_last_event(mid_info));
- ipc_send_message(msg);
- if (mid_info->config->rfm_delay) {
- apr_status_t status;
- status = apr_thread_create(&mid_info->mid_rfmsleep_td, NULL, &rfm_sleep, mid_info, mid_info->pool);
- if (status != APR_SUCCESS) {
- char message[100];
- MLGE("MID: MID rfm_sleep thread creation failure: %s",
- apr_strerror(status, message, sizeof(message)));
- goto error_exit_shutdown;
- }
- mid_info->state = STATE_MODINF_UP;
- goto clean_exit;
- }
- if (mid_info->config->enable_at_channel) {
- if (mid_at_chnl_open(mid_info)) {
- MLGE("AT: Unable to open AT channel. MID will shutdown the modem.");
- goto error_exit_shutdown;
- }
- mid_info->state = STATE_MODINF_UP;
- goto clean_exit;
- }
- /* We just set the MID_CFRDY_EVT event and enter the MODINF_UP state so */
- /* so we can handle the code at the same place */
- SET_FLAG(mid_info->event, MID_CFRDY_EVT);
- MLGD("STMACH: MID_CFRDY_EVT event set.");
- mid_info->state = STATE_MODINF_UP;
- clean_exit:
- if (mid_info->fw_upgr_flash_reply_msg) {
- if (ipc_send_async_reply(&mid_info->fw_upgr_flash_reply_msg, "OK"))
- MLGE("DBUS: Failed to send fw upgrade reply");
- }
- return MID_CLEAR_EVENT;
- error_exit…
Large files files are truncated, but you can click here to view the full file