aboutsummaryrefslogtreecommitdiffstats
path: root/tools/ipc-modem.c
diff options
context:
space:
mode:
Diffstat (limited to 'tools/ipc-modem.c')
-rw-r--r--tools/ipc-modem.c569
1 files changed, 569 insertions, 0 deletions
diff --git a/tools/ipc-modem.c b/tools/ipc-modem.c
new file mode 100644
index 0000000..6e574bd
--- /dev/null
+++ b/tools/ipc-modem.c
@@ -0,0 +1,569 @@
+/*
+ * This file is part of libsamsung-ipc.
+ *
+ * Copyright (C) 2011 Simon Busch <morphis@gravedo.de>
+ * Copyright (C) 2011 Paul Kocialkowsk <contact@paulk.fr>
+ *
+ * libsamsung-ipc is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * libsamsung-ipc is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with libsamsung-ipc. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <unistd.h>
+#include <stdint.h>
+#include <stdbool.h>
+#include <termios.h>
+#include <fcntl.h>
+#include <string.h>
+#include <sys/ioctl.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+#include <pthread.h>
+#include <getopt.h>
+
+#include <samsung-ipc.h>
+
+#define MODEM_STATE_LPM 0
+#define MODEM_STATE_NORMAL 2
+#define MODEM_STATE_SIM_OK 4
+
+#define DEF_CALL_NUMBER "950"
+#define DEF_SIM_PIN "1234"
+
+int state = MODEM_STATE_LPM;
+int seq = 0;
+int in_call = 0;
+int out_call = 0;
+int call_done = 0;
+
+char sim_pin[8];
+
+int seq_get(void)
+{
+ if(seq == 0xff)
+ seq = 0x00;
+
+ seq++;
+
+ return seq;
+}
+
+void modem_snd_no_mic_mute(struct ipc_client *client)
+{
+ uint8_t data = 0;
+ ipc_client_send(client, seq_get(), IPC_SND_MIC_MUTE_CTRL, IPC_TYPE_SET, (void *) &data, 1);
+}
+
+void modem_snd_clock_ctrl(struct ipc_client *client)
+{
+ uint8_t data = 0x01;
+ ipc_client_send(client, seq_get(), IPC_SND_CLOCK_CTRL, IPC_TYPE_EXEC, (void *) &data, 1);
+}
+
+void modem_snd_spkr_volume_ctrl(struct ipc_client *client)
+{
+ uint16_t data = 0x0411;
+ ipc_client_send(client, seq_get(), IPC_SND_SPKR_VOLUME_CTRL, IPC_TYPE_SET, (void *) &data, 2);
+}
+
+void modem_snd_audio_path_ctrl(struct ipc_client *client)
+{
+ uint8_t data = 0x01;
+ ipc_client_send(client, seq_get(), IPC_SND_AUDIO_PATH_CTRL, IPC_TYPE_SET, (void *) &data, 1);
+}
+
+
+void modem_exec_call_out(struct ipc_client *client, char *num)
+{
+ struct ipc_call_outgoing_data call_out;
+
+ modem_snd_no_mic_mute(client);
+
+ memset(&call_out, 0, sizeof(struct ipc_call_outgoing_data));
+
+ call_out.type = IPC_CALL_TYPE_VOICE;
+ call_out.identity = IPC_CALL_IDENTITY_DEFAULT;
+ call_out.number_length=strlen(num);
+ /* 0x21 = +33 */
+ call_out.prefix=IPC_CALL_PREFIX_NONE; //0x21;//IPC_CALL_PREFIX_NONE;
+ memcpy(call_out.number, num, call_out.number_length);
+
+ ipc_client_send(client, seq_get(), IPC_CALL_OUTGOING, IPC_TYPE_EXEC, (void *) &call_out, sizeof(struct ipc_call_outgoing_data));
+
+ out_call = 1;
+
+ modem_snd_no_mic_mute(client);
+ modem_snd_spkr_volume_ctrl(client);
+ modem_snd_audio_path_ctrl(client);
+}
+
+void modem_exec_call_answer(struct ipc_client *client)
+{
+ modem_snd_clock_ctrl(client);
+
+ ipc_client_send(client, seq_get(), IPC_CALL_ANSWER, IPC_TYPE_EXEC, NULL, 0);
+
+ modem_snd_no_mic_mute(client);
+}
+
+void modem_get_call_list(struct ipc_client *client)
+{
+ ipc_client_send(client, seq_get(), IPC_CALL_LIST, IPC_TYPE_GET, NULL, 0);
+
+ modem_snd_no_mic_mute(client);
+}
+
+void modem_exec_power_normal(struct ipc_client *client)
+{
+ uint16_t data = 0x0202;
+ ipc_client_send(client, seq_get(), IPC_PWR_PHONE_STATE, IPC_TYPE_EXEC, (void *) &data, sizeof(data));
+}
+
+void modem_set_sms_device_ready(struct ipc_client *client)
+{
+ ipc_client_send(client, seq_get(), IPC_SMS_DEVICE_READY, IPC_TYPE_SET, NULL, 0);
+}
+
+void modem_set_sec_pin_status(struct ipc_client *client, char *pin1, char *pin2)
+{
+ struct ipc_sec_pin_status_request_data pin_status;
+
+ printf("[I] Sending PIN1 unlock request\n");
+
+ ipc_sec_pin_status_setup(&pin_status, IPC_SEC_PIN_TYPE_PIN1, pin1, pin2);
+ ipc_client_send(client, seq_get(), IPC_SEC_PIN_STATUS, IPC_TYPE_SET, (void *) &pin_status, sizeof(pin_status));
+}
+
+void modem_response_sec(struct ipc_client *client, struct ipc_message *resp)
+{
+ struct ipc_sec_pin_status_response_data *sim_status;
+ unsigned char type;
+ int status;
+ char *data;
+
+ switch(resp->command)
+ {
+ case IPC_SEC_PIN_STATUS :
+ sim_status = (struct ipc_sec_pin_status_response_data *)resp->data;
+
+ switch(sim_status->status)
+ {
+ case IPC_SEC_PIN_STATUS_CARD_NOT_PRESENT:
+ printf("[I] SIM card is definitely absent\n");
+ break;
+ case IPC_SEC_PIN_STATUS_LOCK_SC:
+ switch(sim_status->facility_lock)
+ {
+ case IPC_SEC_FACILITY_LOCK_TYPE_SC_PIN1_REQ:
+ printf("[I] We need the PIN1 to unlock the card!\n");
+ if(strlen(sim_pin) > 0) {
+ modem_set_sec_pin_status(client, sim_pin, NULL);
+ } else {
+ printf("[E] No SIM Pin, use --pin\n");
+ }
+ break;
+ case IPC_SEC_FACILITY_LOCK_TYPE_SC_PUK_REQ:
+ printf("[I] Please provide the SIM card PUK!\n");
+ break;
+ case IPC_SEC_FACILITY_LOCK_TYPE_SC_CARD_BLOCKED:
+ printf("[I] Ouch, the SIM Card is blocked.\n");
+ break;
+ }
+ break;
+ case IPC_SEC_PIN_STATUS_INIT_COMPLETE:
+ printf("[3] SIM init complete\n");
+ if(state == MODEM_STATE_NORMAL)
+ state = MODEM_STATE_SIM_OK;
+
+ break;
+ case IPC_SEC_PIN_STATUS_PB_INIT_COMPLETE:
+ printf("[I] SIM Phone Book init complete\n");
+ break;
+ }
+ break;
+ case IPC_SEC_SIM_ICC_TYPE:
+ type = *((char *) resp->data);
+ switch(type)
+ {
+ case IPC_SEC_SIM_CARD_TYPE_UNKNOWN:
+ printf("[I] No SIM card type: unknown (absent?)\n");
+ break;
+ case IPC_SEC_SIM_CARD_TYPE_SIM:
+ case IPC_SEC_SIM_CARD_TYPE_USIM:
+ printf("[I] SIM card found\n");
+ break;
+ }
+ break;
+ }
+}
+
+void modem_response_sms(struct ipc_client *client, struct ipc_message *resp)
+{
+ switch(resp->command)
+ {
+ case IPC_SMS_DEVICE_READY:
+ if(state == MODEM_STATE_LPM)
+ {
+ printf("[4] Modem is ready, requesting normal power mode\n");
+ modem_exec_power_normal(client);
+ }
+ else if(state == MODEM_STATE_SIM_OK)
+ {
+ printf("[5] Modem is fully ready\n");
+ modem_set_sms_device_ready(client);
+ }
+ break;
+ }
+}
+
+void modem_response_call(struct ipc_client *client, struct ipc_message *resp)
+{
+ struct ipc_call_status_data *stat;
+
+ switch(resp->command)
+ {
+ case IPC_CALL_LIST:
+/*
+ if(in_call)
+ modem_exec_call_answer(client);
+ if(out_call)
+ modem_snd_no_mic_mute(client);
+*/
+ break;
+ case IPC_CALL_INCOMING:
+ printf("[I] Got an incoming call!\n");
+ in_call = 1;
+ modem_get_call_list(client);
+ break;
+ case IPC_CALL_STATUS:
+ stat = (struct ipc_call_status_data *)resp->data;
+
+ if(stat->status == IPC_CALL_STATUS_DIALING)
+ {
+ printf("[I] Sending clock ctrl and restore alsa\n");
+ modem_snd_clock_ctrl(client);
+// system("alsa_ctl -f /data/alsa_state_modem restore");
+
+ printf("[I] CALL STATUS DIALING!!!\n");
+
+ modem_snd_spkr_volume_ctrl(client);
+ modem_snd_audio_path_ctrl(client);
+
+ modem_get_call_list(client);
+ }
+ if(stat->status == IPC_CALL_STATUS_CONNECTED)
+ {
+ printf("[I] CALL STATUS CONNECTED!!!\n");
+ modem_snd_no_mic_mute(client);
+ }
+ if(stat->status == IPC_CALL_STATUS_RELEASED)
+ {
+ printf("[I] CALL STATUS RELEASED!!!\n");
+ modem_snd_no_mic_mute(client);
+ }
+ break;
+ }
+}
+
+void modem_response_pwr(struct ipc_client *client, struct ipc_message *resp)
+{
+ int state_n;
+
+ switch(resp->command)
+ {
+ case IPC_PWR_PHONE_PWR_UP:
+ printf("[2] Phone is powered up (LPM)!\n");
+ state = MODEM_STATE_LPM;
+ break;
+
+ case IPC_PWR_PHONE_STATE:
+ state_n = *((int *)resp->data);
+#if 0
+ switch(state_n)
+ {
+ /* FIXME: Broken */
+ case IPC_PWR_PHONE_STATE_NORMAL:
+ printf("Power state is now: NORMAL\n");
+ break;
+ case IPC_PWR_PHONE_STATE_LPM:
+ printf("Power state is now: LPM (Low Power Mode)?\n");
+ break;
+ }
+#endif
+ state = state_n;
+ break;
+
+ }
+}
+
+void modem_response_net(struct ipc_client *client, struct ipc_message *resp)
+{
+ struct ipc_net_regist_response_data *regi;
+ struct ipc_net_plmn_entry *plmn;
+ char mnc[6];
+
+ switch(resp->command)
+ {
+ case IPC_NET_REGIST:
+ regi = (struct ipc_net_regist_response_data *) resp->data;
+ if(regi->status == IPC_NET_REGISTRATION_STATUS_HOME)
+ {
+ printf("[I] Registered with network successfully!\n");
+
+ }
+ break;
+ case IPC_NET_SERVING_NETWORK:
+
+ memcpy(mnc, (char *)((char *) resp->data + 3), 5);
+ mnc[5]=0;
+ printf("[6] Registered with network! Got PLMN (Mobile Network Code): '%s'\n", mnc);
+/*
+ if(call_done == 0)
+ {
+ printf("Requesting outgoing call to %s!\n", DEF_CALL_NUMBER);
+ modem_exec_call_out(client, DEF_CALL_NUMBER);
+ }
+ call_done = 1;
+*/
+ break;
+ }
+}
+
+void modem_response_handle(struct ipc_client *client, struct ipc_message *resp)
+{
+ switch(IPC_GROUP(resp->command))
+ {
+ case IPC_GROUP_NET:
+ modem_response_net(client, resp);
+ break;
+ case IPC_GROUP_PWR:
+ modem_response_pwr(client, resp);
+ break;
+ case IPC_GROUP_SEC:
+ modem_response_sec(client, resp);
+ break;
+ case IPC_GROUP_SMS:
+ modem_response_sms(client, resp);
+ break;
+ case IPC_GROUP_CALL:
+ modem_response_call(client, resp);
+ break;
+ case IPC_GROUP_DISP:
+ if(in_call)
+ modem_snd_no_mic_mute(client);
+ break;
+ }
+}
+
+
+int modem_read_loop(struct ipc_client *client)
+{
+ struct ipc_message resp;
+ int rc;
+
+ memset(&resp, 0, sizeof(resp));
+
+ while(1) {
+ usleep(3000);
+
+ rc = ipc_client_poll(client, NULL);
+ if (rc < 0) {
+ continue;
+ }
+
+ rc = ipc_client_recv(client, &resp);
+ if(rc < 0) {
+ printf("[E] Can't RECV from modem: please run this again\n");
+ break;
+ }
+
+ modem_response_handle(client, &resp);
+
+ if(resp.data != NULL)
+ free(resp.data);
+ }
+
+ return 0;
+}
+
+void modem_log_handler(void *user_data, const char *msg)
+{
+ int i, l;
+ char *message;
+
+ message = strdup(msg);
+ l = strlen(message);
+
+ if(l > 1) {
+ for(i=l ; i > 0 ; i--)
+ {
+ if(message[i] == '\n') {
+ message[i] = 0;
+ } else if(message[i] != 0) {
+ break;
+ }
+ }
+
+ printf("[D] %s\n", message);
+ }
+
+ free(message);
+}
+
+void modem_log_handler_quiet(void *user_data, const char *msg)
+{
+ return;
+}
+
+int modem_start(struct ipc_client *client)
+{
+ int rc = -1;
+
+ ipc_client_data_create(client);
+ ipc_client_boot(client);
+
+ usleep(300);
+
+ rc = ipc_client_open(client);
+ if(rc < 0)
+ return -1;
+
+ rc = ipc_client_power_on(client);
+ if(rc < 0)
+ return -1;
+
+ return 0;
+}
+
+int modem_stop(struct ipc_client *client)
+{
+ ipc_client_power_off(client);
+ ipc_client_close(client);
+
+ return 0;
+}
+
+void print_help()
+{
+ printf("usage: ipc-modem <command>\n");
+ printf("commands:\n");
+ printf("\tstart boot modem and start read loop\n");
+ printf("\tboot boot modem only\n");
+ printf("\tpower-on power on the modem\n");
+ printf("\tpower-off power off the modem\n");
+ printf("arguments:\n");
+ printf("\t--debug enable debug messages\n");
+ printf("\t--pin=[PIN] provide SIM card PIN\n");
+}
+
+int main(int argc, char *argv[])
+{
+ struct ipc_client *client_fmt;
+ int c = 0;
+ int opt_i = 0;
+ int rc = -1;
+ int debug = 0;
+
+ struct option opt_l[] = {
+ {"help", no_argument, 0, 0 },
+ {"debug", no_argument, 0, 0 },
+ {"pin", required_argument, 0, 0 },
+ {0, 0, 0, 0 }
+ };
+
+ if (argc < 2) {
+ print_help();
+ exit(1);
+ }
+
+ while(c >= 0) {
+ c = getopt_long(argc, argv, "", opt_l, &opt_i);
+ if(c < 0)
+ break;
+
+ switch(c) {
+ case 0:
+ if (strncmp(opt_l[opt_i].name, "help", 4) == 0) {
+ print_help();
+ exit(1);
+ } else if(strcmp(opt_l[opt_i].name, "debug") == 0) {
+ debug = 1;
+ printf("[I] Debug enabled\n");
+ } else if(strcmp(opt_l[opt_i].name, "pin") == 0) {
+ if(optarg) {
+ if(strlen(optarg) < 8) {
+ printf("[I] Got SIM PIN!\n");
+ memcpy(sim_pin, optarg, 8);
+ } else {
+ printf("[E] SIM PIN is too long!\n");
+ return 1;
+ }
+ }
+ }
+ break;
+ }
+ }
+
+ client_fmt = ipc_client_create(IPC_CLIENT_TYPE_FMT);
+
+ if (client_fmt == 0) {
+ printf("[E] Could not create IPC client; aborting ...\n");
+ goto modem_quit;
+ }
+
+ if (debug == 0)
+ ipc_client_log_callback_register(client_fmt, modem_log_handler_quiet, NULL);
+ else ipc_client_log_callback_register(client_fmt, modem_log_handler, NULL);
+
+ while(opt_i < argc) {
+ if(strncmp(argv[optind], "power-on", 8) == 0) {
+ if (ipc_client_power_on(client_fmt) < 0)
+ printf("[E] Something went wrong while powering modem on\n");
+ goto modem_quit;
+ } else if(strncmp(argv[optind], "power-off", 9) == 0) {
+ if (ipc_client_power_off(client_fmt) < 0)
+ printf("[E] Something went wrong while powering modem off\n");
+ goto modem_quit;
+ } else if (strncmp(argv[optind], "boot", 9) == 0) {
+ ipc_client_boot(client_fmt);
+ } else if(strncmp(argv[optind], "start", 5) == 0) {
+ printf("[0] Starting modem on FMT client\n");
+ rc = modem_start(client_fmt);
+ if(rc < 0) {
+ printf("[E] Something went wrong\n");
+ modem_stop(client_fmt);
+ return 1;
+ }
+
+ printf("[1] Starting modem_read_loop on FMT client\n");
+ modem_read_loop(client_fmt);
+
+ modem_stop(client_fmt);
+ } else {
+ printf("[E] Unknown argument: '%s'\n", argv[optind]);
+ print_help();
+ return 1;
+ }
+
+ optind++;
+ }
+
+modem_quit:
+ if (client_fmt != 0)
+ ipc_client_destroy(client_fmt);
+
+ return 0;
+}
+
+// vim:ts=4:sw=4:expandtab