--- /dev/null
+/*
+ * tel-plugin-imcmodem
+ *
+ * Copyright (c) 2012 Samsung Electronics Co., Ltd. All rights reserved.
+ *
+ * Contact: Kyoungyoup Park <gynaru.park@samsung.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.
+ */
+
+#include <stdio.h>
+#include <string.h>
+#include <pthread.h>
+#include <unistd.h>
+#include <stdlib.h>
+#include <time.h>
+
+#include <glib.h>
+
+#include <tcore.h>
+#include <server.h>
+#include <plugin.h>
+#include <storage.h>
+#include <user_request.h>
+#include <core_object.h>
+#include <hal.h>
+#include <at.h>
+#include <mux.h>
+
+#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");
+ }
+}
#include <unistd.h>
#include <stdlib.h>
#include <time.h>
-#include <sys/utsname.h>
+#include <fcntl.h>
+#include <sys/ioctl.h>
#include <glib.h>
#include <hal.h>
#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;
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,
#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)
{
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;
}