From 7dea2d4dca8aad1f2d73d36ebec4fa6236da521a Mon Sep 17 00:00:00 2001 From: Suresh Kumar Narasimhaiah Date: Fri, 15 Mar 2013 01:23:31 +0530 Subject: [PATCH] Changes to Modem Interface Plug-in based on New Design for Tizen2.1. Change-Id: I67bdeb96045cec1a1d04adf31d7a450661175d01 --- CMakeLists.txt | 1 + include/config.h | 35 ++++ include/vnet.h | 19 +- src/config.c | 381 ++++++++++++++++++++++++++++++++++++++++ src/desc-imcmodem.c | 496 +++++++++++++++++++++++++++++++++------------------- src/vnet.c | 77 ++++---- 6 files changed, 791 insertions(+), 218 deletions(-) create mode 100644 include/config.h create mode 100644 src/config.c diff --git a/CMakeLists.txt b/CMakeLists.txt index 1ec7799..704ee44 100755 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -32,6 +32,7 @@ MESSAGE(${CMAKE_EXE_LINKER_FLAGS}) SET(SRCS src/desc-imcmodem.c src/vnet.c + src/config.c ) diff --git a/include/config.h b/include/config.h new file mode 100644 index 0000000..fb0c534 --- /dev/null +++ b/include/config.h @@ -0,0 +1,35 @@ +/* + * tel-plugin-imcmodem + * + * Copyright (c) 2012 Samsung Electronics Co., Ltd. All rights reserved. + * + * Contact: Kyoungyoup Park + * + * 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. + */ + +#ifndef _CONFIG_H_ +#define _CONFIG_H_ + +#ifdef __cplusplus +extern "C" { +#endif + +void config_check_cp_power(TcoreHal *hal); + + +#ifdef __cplusplus +} +#endif /* __cplusplus */ + +#endif /* _CONFIG_H_ */ diff --git a/include/vnet.h b/include/vnet.h index 5689f76..5c81e6c 100644 --- a/include/vnet.h +++ b/include/vnet.h @@ -18,17 +18,17 @@ * limitations under the License. */ - #ifndef _VNET_H_ #define _VNET_H_ - #ifdef __cplusplus extern "C" { #endif +/* CP states */ enum vnet_cp_state { - VNET_CP_STATE_OFFLINE, + VNET_CP_STATE_UNKNOWN = -1, + VNET_CP_STATE_OFFLINE = 0, VNET_CP_STATE_CRASH_RESET, VNET_CP_STATE_CRASH_EXIT, VNET_CP_STATE_BOOTING, @@ -37,18 +37,17 @@ enum vnet_cp_state { VNET_CP_STATE_LOADER_DONE, }; -void vnet_start_cp_ramdump( void ); -void vnet_start_cp_reset( void ); -int vnet_get_cp_state( int fd ); +void vnet_start_cp_ramdump( void ); +void vnet_start_cp_reset( void ); -int vnet_rfs0_open( void ); -int vnet_ipc0_open( void ); +enum vnet_cp_state vnet_get_cp_state( int fd ); +int vnet_rfs0_open( void ); +int vnet_ipc0_open( void ); #ifdef __cplusplus } #endif /* __cplusplus */ -#endif - +#endif /* _VNET_H_ */ diff --git a/src/config.c b/src/config.c new file mode 100644 index 0000000..7390015 --- /dev/null +++ b/src/config.c @@ -0,0 +1,381 @@ +/* + * tel-plugin-imcmodem + * + * Copyright (c) 2012 Samsung Electronics Co., Ltd. All rights reserved. + * + * Contact: Kyoungyoup Park + * + * 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. + */ + +#include +#include +#include +#include +#include +#include + +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "config.h" + +#define IMC_MODEM_PLUGIN_NAME "imc-plugin.so" + +#define IMC_CMUX_MAX_CHANNELS 7 +#define IMC_CMUX_MAX_BUFFER_SIZE 1024 + +/* CP States */ +#define IMC_AT_CPAS_RESULT_READY 0 +#define IMC_AT_CPAS_RESULT_UNAVAIL 1 +#define IMC_AT_CPAS_RESULT_UNKNOWN 2 +#define IMC_AT_CPAS_RESULT_RINGING 3 +#define IMC_AT_CPAS_RESULT_CALL_PROGRESS 4 +#define IMC_AT_CPAS_RESULT_ASLEEP 5 + +/* Maximum Core objects per Logical HAL (indirectly per Channel) */ +#define MAX_CORE_OBJECTS_PER_CHANNEL 3 + +/* + * List of supported Core Object types + * + * CMUX Channels [0-7] - + * Channel 0 - Control Channel for CMUX + * Channel 1 - CALL + * Channel 2 - SIM & PHONEBOOK + * Channel 3 - SAT & SAP + * Channel 4 - SMS + * Channel 5 - SS + * Channel 6 - NETWORK & GPS + * Channel 7 - MODEM & PS + */ +unsigned int + supported_modules[IMC_CMUX_MAX_CHANNELS+1][MAX_CORE_OBJECTS_PER_CHANNEL] = +{ + /* + * Channel 0 - CMUX Control Channel + * No Core Objects would be assigned to this channel + */ + {0, 0, 0}, + /* Channel 1 */ + {CORE_OBJECT_TYPE_CALL, 0, 0}, + /* Channel 2 */ + {CORE_OBJECT_TYPE_SIM, CORE_OBJECT_TYPE_PHONEBOOK, 0}, + /* Channel 3 */ + {CORE_OBJECT_TYPE_SAT, CORE_OBJECT_TYPE_SAP, 0}, + /* Channel 4 */ + {CORE_OBJECT_TYPE_SMS, 0, 0}, + /* Channel 5 */ + {CORE_OBJECT_TYPE_SS, 0, 0}, + /* Channel 6 */ + {CORE_OBJECT_TYPE_NETWORK, CORE_OBJECT_TYPE_GPS, 0}, + /* Channel 7 */ + {CORE_OBJECT_TYPE_MODEM, CORE_OBJECT_TYPE_PS, 0}, +}; + +static gboolean _check_cp_poweron(TcoreHal *hal); +static void _send_enable_logging_command(TcoreHal *hal); + +static void _on_confirmation_send_message(TcorePending *pending, + gboolean result, void *user_data) +{ + dbg("Message send confirmation"); + + if (result == FALSE) { /* Fail */ + dbg("SEND FAIL"); + } else { + dbg("SEND OK"); + } +} +static void _assign_objects_to_hal(int channel_id, TcoreHal *hal) +{ + TcorePlugin *plugin; + gboolean ret; + int i; + + plugin = tcore_hal_ref_plugin(hal); + + for (i = 0 ; i < MAX_CORE_OBJECTS_PER_CHANNEL ; i++) { + if (supported_modules[channel_id][i] == 0) + continue; + + /* Add Core Object type for specific 'hal' */ + ret = tcore_server_add_cp_mapping_tbl_entry(plugin, + supported_modules[channel_id][i], hal); + if (ret == TRUE) { + dbg("Core Object Type: [0x%x] - Success"); + } else { + err("Core Object Type: [0x%x] - Fail"); + } + } +} + +static void _on_cmux_setup_complete(gpointer user_data) +{ + TcoreHal *hal = user_data; + TcorePlugin *plugin; + dbg("MUX Setup - COMPLETE"); + + if (user_data == NULL) + return; + + plugin = tcore_hal_ref_plugin(hal); + + /* Print all the HALs and Core Objects for the Plug-in */ + tcore_server_print_modems(plugin); + + /* Load Modem Plug-in */ + tcore_server_load_modem_plugin(tcore_plugin_ref_server(plugin), + plugin, IMC_MODEM_PLUGIN_NAME); +} + +static void _on_cmux_channel_setup(int channel_id, TcoreHal *hal, + gpointer user_data) +{ + TcorePlugin *plugin; + TcoreHal *phy_hal; + if ((hal == NULL) || (user_data == NULL)) + return; + + if ((channel_id == 0) + || (channel_id > IMC_CMUX_MAX_CHANNELS)) { + err("Control Channel"); + return; + } + + phy_hal = user_data; + plugin = tcore_hal_ref_plugin(hal); + + dbg("Channel ID: [%d] Logical HAL: [0x%x]", channel_id, hal); + + /* Assign specifc Core Object types to the Logical HAL (CMUX Channel) */ + _assign_objects_to_hal(channel_id, hal); +} + +static void _on_response_cmux_init(TcorePending *p, int data_len, + const void *data, void *user_data) +{ + const TcoreATResponse *resp = data; + TcoreHal *hal = user_data; + TReturn ret; + + if ((resp != NULL) + && resp->success) { + dbg("Initialize CMUX - [OK]"); + + /* Setup Internal CMUX */ + ret = tcore_cmux_setup_internal_mux(CMUX_MODE_BASIC, + IMC_CMUX_MAX_CHANNELS, + IMC_CMUX_MAX_BUFFER_SIZE, hal, + _on_cmux_channel_setup, hal, + _on_cmux_setup_complete, hal); + } else { + err("Initialize CMUX - [NOK]"); + } +} + +static void _on_response_enable_logging(TcorePending *p, + int data_len, const void *data, void *user_data) +{ + const TcoreATResponse *resp = data; + TcoreHal *hal = user_data; + TReturn ret; + + if ((resp != NULL) + && resp->success) { + dbg("Enable CP logging - [OK]"); + } else { + err("Enable CP logging - [NOK]"); + } + + /* Initialize Internal MUX (CMUX) */ + ret = tcore_cmux_init(hal, 0, _on_response_cmux_init, hal); + if (ret != TCORE_RETURN_SUCCESS) { + err("Failed to initialize CMUX - Error: [0x%x]", ret); + } else { + dbg("Successfully sent CMUX init to CP"); + } +} + +static void _on_timeout_check_cp_poweron(TcorePending *p, void *user_data) +{ + TcoreHal *hal = user_data; + unsigned int data_len = 0; + char *data = "AT+CPAS"; + + data_len = sizeof(data); + + dbg("Resending Command: [%s] Command Length: [%d]", data, data_len); + + /* + * Retransmit 1st AT command (AT+CPAS) directly via HAL without disturbing + * pending queue. + * HAL was passed as user_data, re-using it + */ + tcore_hal_send_data(hal, data_len, (void *)data); +} + +static void _on_response_check_cp_poweron(TcorePending *pending, + int data_len, const void *data, void *user_data) +{ + const TcoreATResponse *resp = data; + TcoreHal *hal = user_data; + + GSList *tokens = NULL; + const char *line; + gboolean bpoweron = FALSE; + int response = 0; + + if ((resp != NULL) + && resp->success) { + dbg("Check CP POWER - [OK]"); + + /* Parse AT Response */ + if (resp->lines) { + line = (const char *) resp->lines->data; + tokens = tcore_at_tok_new(line); + if (g_slist_length(tokens) != 1) { + err("Invalid message"); + goto ERROR; + } + } + + response = atoi(g_slist_nth_data(tokens, 0)); + dbg("CPAS State: [%d]", response); + + switch (response) { + case IMC_AT_CPAS_RESULT_READY: + case IMC_AT_CPAS_RESULT_RINGING: + case IMC_AT_CPAS_RESULT_CALL_PROGRESS: + case IMC_AT_CPAS_RESULT_ASLEEP: + dbg("CP Power ON!!!"); + bpoweron = TRUE; + break; + + case IMC_AT_CPAS_RESULT_UNAVAIL: + case IMC_AT_CPAS_RESULT_UNKNOWN: + default: + err("Value is Unvailable/Unknown - but CP responded - proceed with Power ON!!!"); + bpoweron = TRUE; + break; + } + } else { + dbg("Check CP POWER - [NOK]"); + } + +ERROR: + /* Free tokens */ + tcore_at_tok_free(tokens); + + if (bpoweron == TRUE) { + dbg("CP Power ON received"); + + /* Enable Logging */ + _send_enable_logging_command(hal); + } else { + err("CP is not ready, send CPAS again"); + _check_cp_poweron(hal); + } + return; +} + +static void _send_enable_logging_command(TcoreHal *hal) +{ + TcoreATRequest *at_req = NULL; + TcorePending *pending = NULL; + + dbg("Sending Trace enabling command for CP logging"); + + /* Create Pending request */ + pending = tcore_pending_new(NULL, 0); + + /* Create AT Request */ + at_req = tcore_at_request_new("at+xsystrace=1,\"digrf=1;bb_sw=1;3g_sw=1\",\"digrf=0x84\",\"oct=4\";+xsystrace=11;+trace=1", + NULL, TCORE_AT_NO_RESULT); + + + dbg("AT-Command: [%s] Prefix(if any): [%s] Command length: [%d]", + at_req->cmd, at_req->prefix, strlen(at_req->cmd)); + + /* Set request data and register Response and Send callbacks */ + tcore_pending_set_request_data(pending, 0, at_req); + tcore_pending_set_response_callback(pending, _on_response_enable_logging, hal); + tcore_pending_set_send_callback(pending, _on_confirmation_send_message, NULL); + + /* Send command to CP */ + if (tcore_hal_send_request(hal, pending) != TCORE_RETURN_SUCCESS) { + err("Failed to send Trace logging command"); + } else { + dbg("Successfully sent Trace logging command"); + } +} + +static gboolean _check_cp_poweron(TcoreHal *hal) +{ + TcoreATRequest *at_req; + TcorePending *pending = NULL; + + /* Create Pending request */ + pending = tcore_pending_new(NULL, 0); + + /* Create AT Request */ + at_req = tcore_at_request_new("AT+CPAS", "+CPAS:", TCORE_AT_SINGLELINE); + + dbg("AT-Command: [%s] Prefix(if any): [%s] Command length: [%d]", + at_req->cmd, at_req->prefix, strlen(at_req->cmd)); + + tcore_pending_set_priority(pending, TCORE_PENDING_PRIORITY_DEFAULT); + + /* Set timeout value and timeout callback */ + tcore_pending_set_timeout(pending, 10); + tcore_pending_set_timeout_callback(pending, _on_timeout_check_cp_poweron, hal); + + /* Set request data and register Response and Send callbacks */ + tcore_pending_set_request_data(pending, 0, at_req); + tcore_pending_set_response_callback(pending, _on_response_check_cp_poweron, hal); + tcore_pending_set_send_callback(pending, _on_confirmation_send_message, NULL); + + /* Send command to CP */ + if (tcore_hal_send_request(hal, pending) != TCORE_RETURN_SUCCESS) { + err("Failed to send CPAS"); + return FALSE; + } else { + dbg("Successfully sent CPAS"); + return TRUE; + } +} + +void config_check_cp_power(TcoreHal *hal) +{ + gboolean ret; + dbg("Entry"); + + if (hal == NULL) + return; + + ret = _check_cp_poweron(hal); + if (ret == TRUE) { + dbg("Successfully sent check CP Power ON command"); + } else { + err("Failed to send check CP Power ON command"); + } +} diff --git a/src/desc-imcmodem.c b/src/desc-imcmodem.c index 20cb586..028578b 100644 --- a/src/desc-imcmodem.c +++ b/src/desc-imcmodem.c @@ -24,7 +24,8 @@ #include #include #include -#include +#include +#include #include @@ -36,6 +37,17 @@ #include #include "vnet.h" +#include "config.h" + +#define IMC_HAL_NAME "imcmodem" +#define IMC_BUFFER_LEN_MAX 4096 + +#define IMC_CP_POWER_ON_TIMEOUT 500 + +#define IMC_MAX_CP_POWER_ON_RETRIES 20 + +#define VNET_CH_PATH_BOOT0 "/dev/umts_boot0" +#define IOCTL_CG_DATA_SEND _IO('o', 0x37) struct vnet_channel { int fd; @@ -49,318 +61,448 @@ struct custom_data { typedef gboolean(*cb_func)(GIOChannel *channel, GIOCondition condition, gpointer data); -static gboolean on_recv_ipc_message(GIOChannel *channel, GIOCondition condition, gpointer data); +static gboolean _on_recv_ipc_message(GIOChannel *channel, GIOCondition condition, gpointer data); + +static guint _register_gio_watch(TcoreHal *plugin, int fd, void *callback); + + +/* Utility function to dump the Input/Output bytes (TX/RX Data) */ +static void _util_hex_dump(char *pad, int size, const void *data) +{ + char buffer[255] = {0, }; + char hex[4] = {0, }; + int i; + unsigned char *ptr; + + if (size <= 0) { + msg("[%s] NO data", pad); + return; + } + + ptr = (unsigned char *)data; + + snprintf(buffer, 255, "%s%04X: ", pad, 0); + for (i = 0; i < size; i++) { + snprintf(hex, 4, "%02X ", ptr[i]); + strcat(buffer, hex); + + if ((i + 1) % 8 == 0) { + if ((i + 1) % 16 == 0) { + msg("%s", buffer); + memset(buffer, 0, 255); + snprintf(buffer, 255, "%s%04X: ", pad, i + 1); + } else { + strcat(buffer, " "); + } + } + } + + msg("%s", buffer); +} + +static guint _register_gio_watch(TcoreHal *hal, int fd, void *callback) +{ + GIOChannel *channel = NULL; + guint source; + + if ((fd < 0) || (callback == NULL)) + return 0; + + /* Create Unix Watch channel */ + channel = g_io_channel_unix_new(fd); -static guint register_gio_watch(TcoreHal *p, int fd, void *callback); + /* Add to Watch list for IO and HUP events */ + source = g_io_add_watch(channel, G_IO_IN | G_IO_HUP, (GIOFunc) callback, hal); + g_io_channel_unref(channel); + channel = NULL; -static TReturn hal_power(TcoreHal *h, gboolean flag); + return source; +} -static gboolean _ipc0_init( TcoreHal *h, struct vnet_channel *ch, cb_func recv_message ) +static gboolean _ipc0_init(TcoreHal *hal, struct vnet_channel *ch, cb_func recv_message) { - if ( !ch->fd ) { - g_source_remove( ch->watch_id ); - close( ch->fd ); + dbg("Entry"); + + /* Remove and close the Watch ID and 'fd' if they already exist */ + if (ch->fd >= 0) { + g_source_remove(ch->watch_id); + close(ch->fd); } + /* Open new 'fd' to communicate to CP */ ch->fd = vnet_ipc0_open(); - if ( ch->fd < 0 ) { - dbg("[ error ] vnet_ipc0_open()"); + if (ch->fd < 0) { + err("Failed to Open Communiation Channel to CP: [%d]", ch->fd); return FALSE; } + dbg("AP-CP Communication channel opened - fd: [%d]", ch->fd); - ch->watch_id = register_gio_watch(h, ch->fd, recv_message); + /* Register Channel for IO */ + ch->watch_id = _register_gio_watch(hal, ch->fd, recv_message); ch->on = TRUE; return ch->on; } -static void _ipc0_deinit( struct vnet_channel *ch ) +static void _ipc0_deinit(struct vnet_channel *ch) { - g_source_remove( ch->watch_id ); - close( ch->fd ); + g_source_remove(ch->watch_id); + close(ch->fd); ch->watch_id = 0; ch->fd = 0; ch->on = FALSE; } - -static gboolean _silent_reset( TcoreHal *h ) +static gboolean _silent_reset(TcoreHal *hal) { - dbg("[ error ] cp crash : strat silent reset"); - tcore_hal_set_power_state(h, FALSE); + dbg("[ERROR] Silent Reset"); - dbg("[ error ] do nothing."); -#if 0 // this is not applicable code, now silent reset is not guaranteed ( 2012, 04, 19 ) + /* Set HAL Poer State to OFF (FALSE) */ + tcore_hal_set_power_state(hal, FALSE); - vnet_start_cp_reset(); - - if ( !hal_power( h, TRUE ) ) { - dbg("[ check ] cp crash : silent reset done"); - return TRUE; - } - -#endif + /* TODO: Need to handle Silent Reset */ return FALSE; } -static gboolean _do_exception_operation( TcoreHal *h, int fd, GIOCondition con ) +static gboolean _do_exception_operation(TcoreHal *hal, int fd, GIOCondition cond) { - int state = -1; - struct custom_data *user_data = tcore_hal_ref_user_data( h ); - - dbg("entrance"); + enum vnet_cp_state state = VNET_CP_STATE_UNKNOWN; + struct custom_data *user_data = tcore_hal_ref_user_data(hal); + dbg("Entry"); - switch ( con ) { + switch (cond) { case G_IO_HUP: { - state = vnet_get_cp_state( fd ); - if ( state < 0 ) { + state = vnet_get_cp_state(fd); + if (state == VNET_CP_STATE_UNKNOWN) { dbg("[ error ] vnet_get_cp_state()"); break; } - switch ( (enum vnet_cp_state)state ) { - case VNET_CP_STATE_CRASH_EXIT: { - dbg("[ error ] cp crash : strat ramdump"); - _ipc0_deinit( &user_data->ipc0 ); - vnet_start_cp_ramdump(); - - state = VNET_CP_STATE_CRASH_RESET; - - - } break; + switch (state) { + case VNET_CP_STATE_CRASH_EXIT: + { + err("CP Crash: Start ramdump"); - case VNET_CP_STATE_CRASH_RESET: { + _ipc0_deinit(&user_data->ipc0); + vnet_start_cp_ramdump(); - _ipc0_deinit( &user_data->ipc0 ); + state = VNET_CP_STATE_CRASH_RESET; + } + break; - if (tcore_hal_get_power_state( h )) { + case VNET_CP_STATE_CRASH_RESET: + { + err("CP Crash Reset"); - state = VNET_CP_STATE_CRASH_RESET; + _ipc0_deinit(&user_data->ipc0); - if ( !_silent_reset( h ) ) { - dbg("[ error ] _silent_reset()"); - break; - } - } + if (tcore_hal_get_power_state(hal) == TRUE) { + state = VNET_CP_STATE_CRASH_RESET; - /* - * if current hal power state is FALSE, 'cp_reset' mean normal power off - * ( it's because of kernel concept ) - */ - state = VNET_CP_STATE_OFFLINE; + if (_silent_reset(hal) == FALSE) { + err("Silent Reset failed!!!"); + break; + } + } - } break; + /* + * if current hal power state is FALSE, 'cp_reset' mean normal power off + * (it's because of kernel concept) + */ + state = VNET_CP_STATE_OFFLINE; - default: - dbg("useless state, state : (0x%x)", state); - return TRUE; } + break; - } break; + default: + err("Unwanted State: [0x%x]", state); + return TRUE; + } + } + break; case G_IO_IN: case G_IO_OUT: case G_IO_PRI: case G_IO_ERR: case G_IO_NVAL: - dbg("[ error ] unknown problem, con : (0x%x)", con); - break; - + dbg("Unknown/Undefined problem - condition: [0x%x]", cond); + break; } - tcore_hal_emit_recv_callback(h, sizeof(int), &state); - - dbg("done"); - + /* Emit receive callback */ + tcore_hal_emit_recv_callback(hal, sizeof(int), &state); return TRUE; } -static gboolean _power_on( gpointer data ) +static gboolean _power_on(gpointer data) { - struct custom_data *user_data = 0; - TcoreHal *h = (TcoreHal*)data; - gboolean ret = 0; + struct custom_data *user_data; + TcoreHal *hal; + gboolean ret; + static int count = 0; + dbg("Entry"); + + hal = (TcoreHal*)data; - user_data = tcore_hal_ref_user_data(h); - if (!user_data) { - dbg("[ error ] tcore_hal_ref_user_data()"); + user_data = tcore_hal_ref_user_data(hal); + if (user_data == NULL) { + err("HAL Custom data is NULL"); return TRUE; } + /* Increment the 'count' */ count++; - ret = _ipc0_init( h, &user_data->ipc0, on_recv_ipc_message ); - if ( !ret ) { - dbg("[ error ] _ipc0_init()"); + /* Create and Open interface to CP */ + ret = _ipc0_init(hal, &user_data->ipc0, _on_recv_ipc_message); + if (ret == FALSE) { + err("Failed to Create/Open CP interface - Try count: [%d]", count); - if ( count > 20 ) { - dbg("[ error ] _ipc0_init() timeout"); + if (count > IMC_MAX_CP_POWER_ON_RETRIES) { + err("Maximum timeout reached: [%d]", count); return FALSE; } return TRUE; } + dbg("Created AP-CP interface"); - tcore_hal_set_power_state(h, TRUE); + /* Set HAL Power State ON (TRUE) */ + tcore_hal_set_power_state(hal, TRUE); + dbg("HAL Power State: Power ON"); + /* CP is ONLINE, send AT+CPAS */ + config_check_cp_power(hal); + + /* To stop the cycle need to return FALSE */ return FALSE; } -static TReturn hal_power(TcoreHal *h, gboolean flag) +static enum tcore_hook_return _on_hal_send(TcoreHal *hal, + unsigned int data_len, void *data, void *user_data) { - if (flag == FALSE) { - /* power off not support */ - return TCORE_RETURN_FAILURE; + msg("\n====== TX data DUMP ======\n"); + _util_hex_dump(" ", data_len, data); + msg("\n====== TX data DUMP ======\n"); + + return TCORE_HOOK_RETURN_CONTINUE; +} + +static void _on_hal_recv(TcoreHal *hal, + unsigned int data_len, const void *data, void *user_data) +{ + msg("\n====== RX data DUMP ======\n"); + _util_hex_dump(" ", data_len, data); + msg("\n====== RX data DUMP ======\n"); +} + +static gboolean _on_recv_ipc_message(GIOChannel *channel, + GIOCondition condition, gpointer data) +{ + TcoreHal *hal = data; + struct custom_data *custom; + char recv_buffer[IMC_BUFFER_LEN_MAX]; + int recv_len = 0; + TReturn ret; + + custom = tcore_hal_ref_user_data(hal); + + /* If the received input is NOT IO, then we need to handle the exception */ + if (condition != G_IO_IN) { + err("[ERROR] Not IO input"); + return _do_exception_operation(hal, custom->ipc0.fd, condition); + } + + memset(recv_buffer, 0x0, IMC_BUFFER_LEN_MAX); + + /* Receive data from device */ + recv_len = read(custom->ipc0.fd, (guchar *)recv_buffer, IMC_BUFFER_LEN_MAX); + if (recv_len < 0) { + err("[READ] recv_len: [%d] Error: [%s]", recv_len, strerror(errno)); + return TRUE; } - g_timeout_add_full( G_PRIORITY_HIGH, 500, _power_on, h, 0 ); + msg("\n---------- [RECV] Length of received data: [%d] ----------\n", recv_len); + + /* Emit response callback */ + tcore_hal_emit_recv_callback(hal, recv_len, recv_buffer); - return TCORE_RETURN_SUCCESS; + /* Dispatch received data to response handler */ + ret = tcore_hal_dispatch_response_data(hal, 0, recv_len, recv_buffer); + msg("\n---------- [RECV FINISH] Receive processing: [%d] ----------\n", ret); + + return TRUE; } -static TReturn hal_send(TcoreHal *h, unsigned int data_len, void *data) +static TReturn _hal_send(TcoreHal *hal, unsigned int data_len, void *data) { int ret; struct custom_data *user_data; - if (tcore_hal_get_power_state(h) == FALSE) + if (tcore_hal_get_power_state(hal) == FALSE) return TCORE_RETURN_FAILURE; - user_data = tcore_hal_ref_user_data(h); + user_data = tcore_hal_ref_user_data(hal); if (!user_data) return TCORE_RETURN_FAILURE; dbg("write (fd=%d, len=%d)", user_data->ipc0.fd, data_len); - ret = write( user_data->ipc0.fd, (guchar *) data, data_len ); + ret = write(user_data->ipc0.fd, (guchar *) data, data_len); if (ret < 0) return TCORE_RETURN_FAILURE; return TCORE_RETURN_SUCCESS;; } -static struct tcore_hal_operations hops = -{ - .power = hal_power, - .send = hal_send, -}; - -static gboolean on_recv_ipc_message(GIOChannel *channel, GIOCondition condition, gpointer data) +static TReturn _hal_setup_netif(CoreObject *co, + TcoreHalSetupNetifCallback func, + void *user_data, unsigned int cid, + gboolean enable) { - TcoreHal *h = data; - struct custom_data *custom; - - #define BUF_LEN_MAX 4096 - char buf[BUF_LEN_MAX]; - int n = 0; - - custom = tcore_hal_ref_user_data(h); + int fd; + int ret = -1; - if ( condition != G_IO_IN ) { - dbg("[ error ] svnet has a problem"); - return _do_exception_operation( h, custom->ipc0.fd, condition ); + /* Open device to send IOCTL command */ + fd = open(VNET_CH_PATH_BOOT0, O_RDWR); + if (fd < 0) { + err("Failed to Open [%s] Error: [%s]", VNET_CH_PATH_BOOT0, strerror(errno)); + return TCORE_RETURN_FAILURE; } - memset(buf, 0, BUF_LEN_MAX); - - n = read(custom->ipc0.fd, (guchar *) buf, BUF_LEN_MAX); - if (n < 0) { - err("read error. return_valute = %d", n); - return TRUE; + /* + * Send IOCTL to change the Channel to Data mode + * + * Presently only 2 Contexts are suported + */ + switch (cid) { + case 1: + { + dbg("Send IOCTL: arg 0x05 (0101) HSIC1, cid: [%d]", cid); + ret = ioctl(fd, IOCTL_CG_DATA_SEND, 0x05); } + break; - msg("--[RECV]-------------------------"); - dbg("recv (len = %d)", n); + case 2: + { + dbg("Send IOCTL: arg 0x0A (1010) HSIC2, cid: [%d]", cid); + ret = ioctl(fd, IOCTL_CG_DATA_SEND, 0xA); + } + break; - tcore_hal_emit_recv_callback(h, n, buf); - msg("--[RECV FINISH]------------------\n"); + default: + { + err("More than 2 Contexts are not supported right now!!! cid: [%d]", cid); + } + } - /* Notice: Mode of any HAL is TCORE_HAL_MODE_AT as default. */ - tcore_hal_dispatch_response_data(h, 0, n, buf); + /* Close 'fd' */ + close(fd); - return TRUE; + if (ret < 0) { + err("[ERROR] IOCTL_CG_DATA_SEND - FAIL [0x%x]", IOCTL_CG_DATA_SEND); + return TCORE_RETURN_FAILURE; + } else { + dbg("[OK] IOCTL_CG_DATA_SEND - PASS [0x%x]", IOCTL_CG_DATA_SEND); + return TCORE_RETURN_SUCCESS; + } } -static guint register_gio_watch(TcoreHal *h, int fd, void *callback) -{ - GIOChannel *channel = NULL; - guint source; - - if (fd < 0 || !callback) - return 0; - - channel = g_io_channel_unix_new(fd); - source = g_io_add_watch(channel, G_IO_IN | G_IO_HUP, (GIOFunc) callback, h); - g_io_channel_unref(channel); - channel = NULL; - - return source; -} +/* HAL Operations */ +static struct tcore_hal_operations hal_ops = { + .power = NULL, + .send = _hal_send, + .setup_netif = _hal_setup_netif, +}; static gboolean on_load() { - struct utsname u; - char *vnet_models[] = { "SMDK4410", "SMDK4212", "TRATS2", "SLP_PQ_LTE", "SLP_NAPLES", "REDWOOD", "TRATS", NULL }; - int i = 0; + dbg("Load!!!"); - memset(&u, 0, sizeof(struct utsname)); - uname(&u); + return TRUE; +} - dbg("u.nodename: [%s]", u.nodename); +static gboolean on_init(TcorePlugin *plugin) +{ + TcoreHal *hal; + struct custom_data *data; + dbg("Init!!!"); - for (i = 0; vnet_models[i]; i++ ) { - if (!g_strcmp0(u.nodename, vnet_models[i])) { - return TRUE; - } + if (plugin == NULL) { + err("'plugin' is NULL"); + return FALSE; } +#if 1 /* TODO - Need to remove this */ /* - * Not supported model - * - unload this plugin. + * CP is NOT coming to ONLINE state, + * but when it is forceffuly reset using the command - + * xmm6262-boot + * it comes back to ONLINE state. + * + * We need to look into this aspect */ + dbg("====== TRIGGERING CP RESET ======"); + vnet_start_cp_reset(); + dbg("====== CP RESET TRIGGERED ======"); + sleep(2); +#endif /* TODO - Need to remove this */ + + /* Custom data for Modem Interface Plug-in */ + data = g_try_new0(struct custom_data, 1); + if (data == NULL) { + err("Failed to allocate memory for Custom data"); + return FALSE; + } + dbg("Created custom data memory"); - return FALSE; -} - -static gboolean on_init(TcorePlugin *p) -{ - TcoreHal *h; - struct custom_data *data; - - if (!p) + /* Create Physical HAL */ + hal = tcore_hal_new(plugin, IMC_HAL_NAME, &hal_ops, TCORE_HAL_MODE_AT); + if (hal == NULL) { + err("Failed to Create Physical HAL"); + g_free(data); return FALSE; + } + dbg("HAL [0x%x] created", hal); - dbg("i'm init!"); + /* Link Custom data to HAL's 'user_data' */ + tcore_hal_link_user_data(hal, data); - data = calloc(sizeof(struct custom_data), 1); - memset(data, 0, sizeof(struct custom_data)); + /* Add callbacks for Send/Receive Hooks */ + tcore_hal_add_send_hook(hal, _on_hal_send, NULL); + tcore_hal_add_recv_callback(hal, _on_hal_recv, NULL); + dbg("Added Send hook and Receive callback"); - - /* - * HAL init - */ - h = tcore_hal_new(p, "6262", &hops, TCORE_HAL_MODE_AT); + /* Set HAL state to Power OFF (FALSE) */ + tcore_hal_set_power_state(hal, FALSE); + dbg("HAL Power State: Power OFF"); - tcore_hal_set_power_state(h, FALSE); - tcore_hal_link_user_data(h, data); + /* Resgister to Server */ + tcore_server_register_modem(tcore_plugin_ref_server(plugin), plugin); + + /* Check CP Power ON */ + g_timeout_add_full(G_PRIORITY_HIGH, IMC_CP_POWER_ON_TIMEOUT, _power_on, hal, 0); return TRUE; } -static void on_unload(TcorePlugin *p) +static void on_unload(TcorePlugin *plugin) { - if (!p) + dbg("Unload!!!"); + + if (plugin == NULL) return; - dbg("i'm unload"); + /* Need to Unload Modem Plugin */ } -struct tcore_plugin_define_desc plugin_define_desc = -{ +/* Modem Interface Plug-in descriptor */ +struct tcore_plugin_define_desc plugin_define_desc = { .name = "imcmodem", .priority = TCORE_PLUGIN_PRIORITY_HIGH, .version = 1, diff --git a/src/vnet.c b/src/vnet.c index 725393b..85383b2 100644 --- a/src/vnet.c +++ b/src/vnet.c @@ -47,12 +47,17 @@ #define __USE_GNU #endif - #define MODEM_IMAGE_PATH "/boot/modem.bin" #define NV_DIR_PATH "/csa/nv" #define NV_FILE_PATH NV_DIR_PATH"/nvdata.bin" -#define VNET_CH_PATH_BOOT0 "/dev/umts_boot0" +/* + * AP-CP comunication devices + */ +/* To track CP bootup */ +#define VNET_CH_PATH_BOOT0 "/dev/umts_boot0" + +/* Control communication channel */ #define VNET_CH_PATH_IPC0 "/dev/umts_ipc0" #define IOCTL_MODEM_STATUS _IO('o', 0x27) @@ -61,79 +66,89 @@ void vnet_start_cp_ramdump() { int ret; ret = system("/usr/bin/xmm6262-boot -o u &"); - dbg("system(/usr/bin/xmm6262-boot -o u &) ret[%d]",ret) + dbg("system(/usr/bin/xmm6262-boot -o u &) ret[%d]", ret) } void vnet_start_cp_reset() { int ret; ret = system("/usr/bin/xmm6262-boot &"); - dbg("system(/usr/bin/xmm6262-boot &) ret[%d]",ret) + dbg("system(/usr/bin/xmm6262-boot &) ret[%d]", ret) } -int vnet_get_cp_state( int fd ) +enum vnet_cp_state vnet_get_cp_state(int fd) { - enum vnet_cp_state state = VNET_CP_STATE_ONLINE; + enum vnet_cp_state state = VNET_CP_STATE_UNKNOWN; + dbg("Entry"); - state = ioctl( fd, IOCTL_MODEM_STATUS ); + /* Get CP state */ + state = ioctl(fd, IOCTL_MODEM_STATUS); - switch ( state ) { + switch (state) { case VNET_CP_STATE_OFFLINE: - dbg("cp state : offline"); + dbg("CP State: OFFLINE"); break; case VNET_CP_STATE_CRASH_RESET: - dbg("cp state : crash_reset"); + dbg("CP State: CRASH RESET"); break; case VNET_CP_STATE_CRASH_EXIT: - dbg("cp state : crash_exit"); + dbg("CP State: CRASH EXIT"); break; case VNET_CP_STATE_BOOTING: - dbg("cp state : boot"); + dbg("CP State: BOOT"); break; case VNET_CP_STATE_ONLINE: - dbg("cp state : online"); + dbg("CP State: ONLINE"); break; case VNET_CP_STATE_NV_REBUILDING: - dbg("cp state : nv rebuild"); + dbg("CP State: NV REBUILD"); break; case VNET_CP_STATE_LOADER_DONE: - dbg("cp state : loader done"); + dbg("CP State: LOADER DONE"); break; + case VNET_CP_STATE_UNKNOWN: default: - dbg("cp state : unknown state"); - return -1; + dbg("CP State: UNKNOWN State - [%d]", state); + break; } - return (int)state; + return state; } int vnet_ipc0_open() { - int state; - int fd = 0; - - fd = open ( VNET_CH_PATH_BOOT0, O_RDWR ); - if ( fd < 0 ) { - dbg("error : open [ %s ] [ %s ]", VNET_CH_PATH_BOOT0, strerror(errno)); + enum vnet_cp_state state; + int fd; + dbg("Entry"); + + /* Opening device to track CP state */ + fd = open(VNET_CH_PATH_BOOT0, O_RDWR); + if (fd < 0) { + err("Failed to Open [%s] Error: [%s]", VNET_CH_PATH_BOOT0, strerror(errno)); return -1; } - state = vnet_get_cp_state( fd ); - if ( (enum vnet_cp_state)state != VNET_CP_STATE_ONLINE ) { + /* Track the state of CP */ + state = vnet_get_cp_state(fd); + dbg("CP State: [%d]", state); + if (state != VNET_CP_STATE_ONLINE) { + err("CP is NOT yet Online!!!"); return -1; - } else { - fd = open ( VNET_CH_PATH_IPC0, O_RDWR ); - if ( fd < 0 ) { - dbg("error : open [ %s ] [ %s ]", VNET_CH_PATH_IPC0, strerror(errno)); + } else { + /* Opening AP-CP Control communication device */ + fd = open(VNET_CH_PATH_IPC0, O_RDWR); + if (fd < 0) { + err("Failed to Open [%s] Error: [%s]", VNET_CH_PATH_IPC0, strerror(errno)); return -1; - } } + } + return fd; } -- 2.7.4