summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorJoerie de Gram <j.de.gram@gmail.com>2011-10-26 18:03:00 +0200
committerJoerie de Gram <j.de.gram@gmail.com>2011-10-29 16:26:26 +0200
commit791fd3e4a946c05d6598f5054075515df6327b7d (patch)
treee45cfbe6eb9a9ce1515c6c1cc81e50761971ad15
downloadhardware_ril_samsung-ril-791fd3e4a946c05d6598f5054075515df6327b7d.zip
hardware_ril_samsung-ril-791fd3e4a946c05d6598f5054075515df6327b7d.tar.gz
hardware_ril_samsung-ril-791fd3e4a946c05d6598f5054075515df6327b7d.tar.bz2
Temporary initial commit
-rw-r--r--Android.mk44
-rw-r--r--call.c184
-rw-r--r--misc.c29
-rw-r--r--net.c84
-rw-r--r--samsung-ril.c539
-rw-r--r--samsung-ril.h99
-rw-r--r--sat.c137
-rw-r--r--sim.c461
-rw-r--r--sms.c130
-rw-r--r--util.c136
-rw-r--r--util.h8
11 files changed, 1851 insertions, 0 deletions
diff --git a/Android.mk b/Android.mk
new file mode 100644
index 0000000..1cee136
--- /dev/null
+++ b/Android.mk
@@ -0,0 +1,44 @@
+# Copyright 2006 The Android Open Source Project
+
+LOCAL_PATH:= $(call my-dir)
+include $(CLEAR_VARS)
+
+LOCAL_SRC_FILES := \
+ call.c \
+ samsung-ril.c \
+ misc.c \
+ net.c \
+ sat.c \
+ sim.c \
+ sms.c \
+ util.c \
+
+LOCAL_SHARED_LIBRARIES := \
+ libcutils libutils libril
+
+LOCAL_STATIC_LIBRARIES := libsamsung-ipc
+
+# for asprinf
+LOCAL_CFLAGS := -D_GNU_SOURCE
+
+LOCAL_C_INCLUDES := external/libsamsung-ipc/include
+
+LOCAL_MODULE_TAGS := optional
+
+LOCAL_PRELINK_MODULE := false
+
+ifeq (foo,foo)
+ #build shared library
+ LOCAL_SHARED_LIBRARIES += \
+ libcutils libutils
+ LOCAL_LDLIBS += -lpthread
+ LOCAL_CFLAGS += -DRIL_SHLIB -DDEVICE_H1
+ LOCAL_MODULE:= libsamsung-ril
+ include $(BUILD_SHARED_LIBRARY)
+else
+ #build executable
+ LOCAL_SHARED_LIBRARIES += \
+ libril
+ LOCAL_MODULE:= samsung-ril
+ include $(BUILD_EXECUTABLE)
+endif
diff --git a/call.c b/call.c
new file mode 100644
index 0000000..4e89e82
--- /dev/null
+++ b/call.c
@@ -0,0 +1,184 @@
+#define LOG_TAG "RIL-CALL"
+#include <utils/Log.h>
+
+#include "samsung-ril.h"
+
+extern const struct RIL_Env *rilenv;
+extern struct radio_state radio;
+extern struct ipc_client *ipc_client;
+
+/**
+ * In: RIL_REQUEST_GET_CURRENT_CALLS
+ * Requests current call list
+ *
+ * Out: IPC_CALL_LIST GET
+ * Requests a list of active calls
+ */
+void requestGetCurrentCalls(RIL_Token t)
+{
+ ipc_client_send_get(IPC_CALL_LIST, getRequestId(t));
+}
+
+/**
+ * In: IPC_CALL_LIST GET
+ * Provides a list of active calls
+ *
+ * Out: RIL_REQUEST_GET_CURRENT_CALLS
+ * Requests current call list
+ */
+void respondCallList(RIL_Token t, void *data, int length)
+{
+ struct ipc_call_list_entry *entry;
+ unsigned char num_entries;
+ char *number, *number_ril;
+ int i;
+
+ num_entries = *((unsigned char*)data);
+ entry = (struct ipc_call_list_entry*)((char*)data+1);
+
+ RIL_Call **calls = (RIL_Call**)malloc(num_entries * sizeof(RIL_Call*));
+
+ for(i = 0; i < num_entries; i++) {
+ RIL_Call *call = (RIL_Call*)malloc(sizeof(RIL_Call));
+
+ /* Number is located after call list entry */
+ number = ((char*)entry) + sizeof(*entry);
+
+ number_ril = (char*)malloc(entry->number_len + 1);
+ memset(number_ril, 0, (entry->number_len + 1));
+ memcpy(number_ril, number, entry->number_len);
+
+ call->state = (entry->state-1); /* FIXME: mapping func */
+ call->index = (entry->idx+1);
+ call->toa = (entry->number_len > 0 && number[0] == '+') ? 145 : 129;
+ call->isMpty = entry->mpty;
+ call->isMT = (entry->term == IPC_CALL_TERM_MT);
+ call->als = 0;
+ call->isVoice = (entry->type == IPC_CALL_TYPE_VOICE);
+ call->isVoicePrivacy = 0;
+ call->number = number_ril;
+ call->numberPresentation = (entry->number_len > 0) ? 0 : 2;
+ call->name = NULL;
+ call->namePresentation = 2;
+ call->uusInfo = NULL;
+
+ calls[i] = call;
+
+ /* Next entry after current number */
+ entry = (struct ipc_call_list_entry*)(number + entry->number_len);
+ }
+
+ RIL_onRequestComplete(t, RIL_E_SUCCESS, calls, (num_entries * sizeof(RIL_Call*)));
+
+ for(i = 0; i < num_entries; i++) {
+ free(calls[i]);
+ }
+
+ free(calls);
+}
+
+/**
+ * In: RIL_REQUEST_HANGUP
+ * Hang up a specific line (like AT+CHLD=1x)
+ *
+ * Out: IPC_CALL_RELEASE EXEC
+ */
+void requestHangup(RIL_Token t)
+{
+ ipc_client_send_exec(IPC_CALL_RELEASE, getRequestId(t));
+
+ /* FIXME: This should actually be sent based on the response from baseband */
+ RIL_onRequestComplete(t, RIL_E_SUCCESS, NULL, 0);
+
+ /* FIXME: Do we really need to send this? */
+ RIL_onUnsolicitedResponse(RIL_UNSOL_RESPONSE_CALL_STATE_CHANGED, NULL, 0);
+}
+
+/**
+ * In: RIL_REQUEST_ANSWER
+ * Answer incoming call
+ *
+ * Out: IPC_CALL_ANSWER
+ */
+void requestAnswer(RIL_Token t)
+{
+ ipc_client_send_exec(IPC_CALL_ANSWER, getRequestId(t));
+
+ /* FIXME: This should actually be sent based on the response from baseband */
+ RIL_onRequestComplete(t, RIL_E_SUCCESS, NULL, 0);
+
+ /* FIXME: Do we really need to send this? */
+ RIL_onUnsolicitedResponse(RIL_UNSOL_RESPONSE_CALL_STATE_CHANGED, NULL, 0);
+}
+
+/**
+ * In: RIL_REQUEST_DIAL
+ * Initiate voice call
+ *
+ * Out: IPC_CALL_OUTGOING
+ */
+void requestDial(RIL_Token t, void *data, size_t datalen)
+{
+ const RIL_Dial *dial = (const RIL_Dial*)data;
+ struct ipc_call_outgoing call;
+ int clir;
+
+ if(strlen(dial->address) > sizeof(call.number)) {
+ printf("Outgoing call number too long\n");
+ return;
+ }
+
+ /* FIXME: separate method? */
+ switch(dial->clir) {
+ case 0:
+ clir = IPC_CALL_IDENTITY_DEFAULT;
+ break;
+ case 1:
+ clir = IPC_CALL_IDENTITY_SHOW;
+ break;
+ case 2:
+ clir = IPC_CALL_IDENTITY_HIDE;
+ break;
+ default:
+ clir = IPC_CALL_IDENTITY_DEFAULT;
+ break;
+ }
+
+ memset(&call, 0x00, sizeof(call));
+
+ call.type = IPC_CALL_TYPE_VOICE;
+ call.identity = clir;
+ call.prefix = IPC_CALL_PREFIX_NONE;
+
+ call.length = strlen(dial->address);
+ memcpy(call.number, dial->address, strlen(dial->address));
+
+ ipc_client_send(ipc_client, IPC_CALL_OUTGOING, IPC_TYPE_EXEC, (unsigned char*)&call, sizeof(call), getRequestId(t));
+
+ /* FIXME: This should actually be sent based on the response from baseband */
+ RIL_onRequestComplete(t, RIL_E_SUCCESS, NULL, 0);
+}
+
+/**
+ * In: RIL_UNSOL_CALL_RING
+ * Ring indication for an incoming call (eg, RING or CRING event).
+ */
+void respondCallIncoming(RIL_Token t, void *data, int length)
+{
+ RIL_onUnsolicitedResponse(RIL_UNSOL_CALL_RING, NULL, 0);
+
+ /* FIXME: Do we really need to send this? */
+ RIL_onUnsolicitedResponse(RIL_UNSOL_RESPONSE_CALL_STATE_CHANGED, NULL, 0);
+}
+
+/**
+ * In: IPC_CALL_STATUS
+ * Indicates that a call's status has changed
+ *
+ * RIL_UNSOL_RESPONSE_CALL_STATE_CHANGED
+ * Indicate when call state has changed
+ */
+void respondCallStatus(RIL_Token t, void *data, int length)
+{
+ RIL_onUnsolicitedResponse(RIL_UNSOL_RESPONSE_CALL_STATE_CHANGED, NULL, 0);
+}
diff --git a/misc.c b/misc.c
new file mode 100644
index 0000000..4f745eb
--- /dev/null
+++ b/misc.c
@@ -0,0 +1,29 @@
+#define LOG_TAG "RIL-MISC"
+#include <utils/Log.h>
+
+#include "samsung-ril.h"
+
+extern const struct RIL_Env *rilenv;
+extern struct radio_state radio;
+extern struct ipc_client *ipc_client;
+
+void requestBasebandVersion(RIL_Token t)
+{
+ if(radio.radio_state != RADIO_STATE_OFF) {
+ ipc_client_send_get(IPC_MISC_ME_VERSION, getRequestId(t));
+ } else {
+ radio.token_baseband_ver = t;
+ }
+}
+
+void respondBasebandVersion(struct ipc_message_info *request)
+{
+ char sw_version[33];
+ struct ipc_misc_me_version *version = (struct ipc_misc_me_version*)request->data;
+
+ memcpy(sw_version, version->sw_version, 32);
+ sw_version[32] = '\0';
+
+ RIL_onRequestComplete(getToken(request->aseq), RIL_E_SUCCESS, sw_version, sizeof(sw_version));
+}
+
diff --git a/net.c b/net.c
new file mode 100644
index 0000000..5f0e2c9
--- /dev/null
+++ b/net.c
@@ -0,0 +1,84 @@
+#define LOG_TAG "RIL-NET"
+#include <utils/Log.h>
+
+#include "samsung-ril.h"
+#include "util.h"
+
+extern const struct RIL_Env *rilenv;
+extern struct radio_state radio;
+extern struct ipc_client *ipc_client;
+
+void requestGPRSRegistrationState(RIL_Token t)
+{
+ struct ipc_net_regist_get message;
+
+ /* We only support one active GPRS registration state request */
+ if(!radio.token_ps) {
+ radio.token_ps = t;
+
+ ipc_net_regist_get(&message, IPC_NET_SERVICE_DOMAIN_GPRS);
+ LOGD("ipc_net_regist [net = %d; domain = %d]", message.net, message.domain);
+ ipc_client_send(ipc_client, IPC_NET_REGIST, IPC_TYPE_GET, (unsigned char*)&message, sizeof(message), getRequestId(t));
+ } else {
+ RIL_onRequestComplete(t, RIL_E_GENERIC_FAILURE, NULL, 0);
+ }
+}
+
+void respondGPRSRegistrationState(struct ipc_message_info *request, struct ipc_net_regist *netinfo)
+{
+ int i;
+ char *response[4];
+
+ asprintf(&response[0], "%d", registatus_ipc2ril(netinfo->reg_state));
+ asprintf(&response[1], "%04x", netinfo->lac);
+ asprintf(&response[2], "%08x", netinfo->cid);
+ asprintf(&response[3], "%d", act_ipc2ril(netinfo->act));
+
+ RIL_onRequestComplete(radio.token_ps, RIL_E_SUCCESS, response, sizeof(response));
+
+ radio.token_ps = 0;
+
+ for(i = 0; i < 4; i++) {
+ free(response[i]);
+ }
+}
+
+void respondNetRegist(struct ipc_message_info *request)
+{
+ if(request->type == IPC_TYPE_NOTI) {
+ memcpy(&radio.netinfo, request->data, sizeof(radio.netinfo));
+ RIL_onUnsolicitedResponse(RIL_UNSOL_RESPONSE_NETWORK_STATE_CHANGED, NULL, 0);
+ } else if(request->type == IPC_TYPE_RESP) {
+ struct ipc_net_regist *netinfo = (struct ipc_net_regist*)request->data;
+
+ if(netinfo->domain == 3) {
+ LOGD("%s: netinfo service domain = ps", __FUNCTION__);
+ respondGPRSRegistrationState(request, netinfo);
+ } else {
+ LOGE("%s: unhandled service domain: %d", __FUNCTION__, netinfo->domain);
+ }
+ } else {
+ LOGE("%s: unhandled ipc method: %d", __FUNCTION__, request->type);
+ }
+}
+
+void requestGetPreferredNetworkType(RIL_Token t)
+{
+ ipc_client_send_get(IPC_NET_MODE_SEL, getRequestId(t));
+}
+
+void respondModeSel(struct ipc_message_info *request)
+{
+ unsigned char ipc_mode = *(unsigned char*)request->data;
+ int ril_mode = modesel_ipc2ril(ipc_mode);
+
+ RIL_onRequestComplete(getToken(request->aseq), RIL_E_SUCCESS, &ril_mode, sizeof(int*));
+}
+
+void requestSetPreferredNetworkType(RIL_Token t, void *data, size_t datalen)
+{
+ int ril_mode = *(int*)data;
+ unsigned char ipc_mode = modesel_ril2ipc(ril_mode);
+
+ ipc_client_send(ipc_client, IPC_NET_MODE_SEL, IPC_TYPE_SET, &ipc_mode, sizeof(ipc_mode), getRequestId(t));
+}
diff --git a/samsung-ril.c b/samsung-ril.c
new file mode 100644
index 0000000..bd9bc7f
--- /dev/null
+++ b/samsung-ril.c
@@ -0,0 +1,539 @@
+#include <telephony/ril.h>
+
+#include <radio.h>
+#include <util.h>
+
+#define LOG_TAG "RIL"
+#include <utils/Log.h>
+
+#include "samsung-ril.h"
+#include "util.h"
+
+#define RIL_VERSION_STRING "Samsung H1 RIL"
+
+struct radio_state radio;
+const struct RIL_Env *rilenv;
+struct ipc_client *ipc_client;
+
+/* Tokens associated with requests */
+RIL_Token request_ids[256];
+int rid = 0;
+
+void start_thread();
+
+int getRequestId(RIL_Token token)
+{
+ int id = (rid++ % 0x7E); //fixme
+ request_ids[id] = token;
+
+ //LOGD("Assigned request id token=%08X id=%02X\n", token, id);
+
+ return id;
+}
+
+void setToken(int id, RIL_Token token)
+{
+ request_ids[id] = token;
+}
+
+RIL_Token getToken(int id)
+{
+ //LOGD("Got token=%08X id=%02X\n", request_ids[id], id);
+ return request_ids[id];
+}
+
+void respondNitz(void *data, int length)
+{
+ struct ipc_misc_time_info *nitz = (struct ipc_misc_time_info*)data;
+ char str[128];
+
+ sprintf(str, "%02u/%02u/%02u,%02u:%02u:%02u+%02d,%02d",
+ nitz->year, nitz->mon, nitz->day, nitz->hour, nitz->min, nitz->sec, nitz->tz, 0);
+
+ RIL_onUnsolicitedResponse(RIL_UNSOL_NITZ_TIME_RECEIVED, str, strlen(str) + 1);
+}
+
+void requestIMEI(RIL_Token t)
+{
+ if(radio.radio_state != RADIO_STATE_OFF) {
+ ipc_client_send_get(IPC_MISC_ME_SN, getRequestId(t));
+ } else {
+ radio.token_imei = t;
+ }
+}
+
+void respondIMEI(RIL_Token t, void *data, int length)
+{
+ struct ipc_misc_me_sn *imei_info;
+ char imei[33];
+ char imeisv[3];
+
+ imei_info = (struct ipc_misc_me_sn*)data;
+
+ if(imei_info->length > 32)
+ return;
+
+ memset(imei, 0, sizeof(imei));
+ memset(imeisv, 0, sizeof(imeisv));
+
+ memcpy(imei, imei_info->imei, imei_info->length);
+
+ /* Last two bytes of IMEI in imei_info are the SV bytes */
+ memcpy(imeisv, (imei_info->imei + imei_info->length - 2), 2);
+
+ /* IMEI */
+ RIL_onRequestComplete(t, RIL_E_SUCCESS, imei, sizeof(char*));
+
+ /* IMEI SV */
+ RIL_onRequestComplete(radio.token_imeisv, RIL_E_SUCCESS, imeisv, sizeof(char*));
+}
+
+void requestIMEISV(RIL_Token t)
+{
+ radio.token_imeisv = t;
+}
+
+void requestOperator(RIL_Token t)
+{
+ ipc_client_send_get(IPC_NET_CURRENT_PLMN, getRequestId(t));
+}
+
+void respondOperator(RIL_Token t, void *data, int length)
+{
+ struct ipc_net_current_plmn *plmndata = (struct ipc_net_current_plmn*)data;
+
+ char plmn[7];
+ memset(plmn, 0, sizeof(plmn));
+ memcpy(plmn, plmndata->plmn, 6);
+
+ if(plmn[5] == '#')
+ plmn[5] = '\0'; //FIXME: remove #?
+
+ char *response[3];
+ asprintf(&response[0], "%s", plmn_lookup(plmn));
+ //asprintf(&response[1], "%s", "Voda NL");
+ response[1] = NULL;
+ response[2] = plmn;
+
+ RIL_onRequestComplete(t, RIL_E_SUCCESS, response, sizeof(response));
+
+ free(response[0]);
+ free(response[1]);
+}
+
+void requestRegistrationState(RIL_Token t)
+{
+ char *response[15];
+ memset(response, 0, sizeof(response));
+
+ asprintf(&response[0], "%d", 1); //FIXME: registration state
+ asprintf(&response[1], "%x", radio.netinfo.lac);
+ asprintf(&response[2], "%x", radio.netinfo.cid);
+ asprintf(&response[3], "%d", 1); //FIXME: network technology
+
+ RIL_onRequestComplete(t, RIL_E_SUCCESS, response, sizeof(response));
+
+ free(response[0]);
+ free(response[1]);
+ free(response[2]);
+}
+
+void requestNwSelectionMode(RIL_Token t)
+{
+ unsigned int mode = 0;
+ RIL_onRequestComplete(t, RIL_E_SUCCESS, &mode, sizeof(mode));
+}
+
+void requestAvailNetworks(RIL_Token t)
+{
+ ipc_client_send_get(IPC_NET_PLMN_LIST, getRequestId(t));
+}
+
+/* FIXME: cleanup struct names & resp[] addressing */
+void respondAvailNetworks(RIL_Token t, void *data, int length)
+{
+ struct ipc_net_plmn_entries *entries_info = (struct ipc_net_plmn_entries*)data;
+ struct ipc_net_plmn_entry *entries = entries_info->data;
+
+ int i ;
+ int size = (4 * entries_info->num * sizeof(char*));
+ int actual_size = 0;
+
+ char **resp = malloc(size);
+ char **resp_ptr = resp;
+
+ for(i = 0; i < entries_info->num; i++) {
+ /* Assumed type for 'emergency only' PLMNs */
+ if(entries[i].type == 0x01)
+ continue;
+
+ char *plmn = plmn_string(entries[i].plmn);
+
+ /* Long (E)ONS */
+ asprintf(&resp_ptr[0], "%s", plmn_lookup(plmn));
+
+ /* Short (E)ONS - FIXME: real short EONS */
+ asprintf(&resp_ptr[1], "%s", plmn_lookup(plmn));
+
+ /* PLMN */
+ asprintf(&resp_ptr[2], "%s", plmn);
+
+ free(plmn);
+
+ /* PLMN status */
+ switch(entries[i].status) {
+ case IPC_NET_PLMN_STATUS_AVAILABLE:
+ asprintf(&resp_ptr[3], "available");
+ break;
+ case IPC_NET_PLMN_STATUS_CURRENT:
+ asprintf(&resp_ptr[3], "current");
+ break;
+ case IPC_NET_PLMN_STATUS_FORBIDDEN:
+ asprintf(&resp_ptr[3], "forbidden");
+ break;
+ default:
+ asprintf(&resp_ptr[3], "unknown");
+ break;
+ }
+
+ actual_size++;
+ resp_ptr += 4;
+ }
+
+ RIL_onRequestComplete(t, RIL_E_SUCCESS, resp, (4 * sizeof(char*) * actual_size));
+
+ /* FIXME: free individual strings */
+ free(resp);
+}
+
+void respondSignalStrength(RIL_Token t, void *data, int length)
+{
+ struct ipc_disp_icon_info *signal_info = (struct ipc_disp_icon_info*)data;
+ int rssi;
+
+ RIL_SignalStrength ss;
+ memset(&ss, 0, sizeof(ss));
+
+ /* Multiplying the number of bars by 3 yields
+ * an asu with an equal number of bars in Android
+ */
+ ss.GW_SignalStrength.signalStrength = (3 * signal_info->rssi);
+ ss.GW_SignalStrength.bitErrorRate = 99;
+
+ RIL_onUnsolicitedResponse(RIL_UNSOL_SIGNAL_STRENGTH, &ss, sizeof(ss));
+}
+
+void requestPower(RIL_Token t, void *data, size_t datalen)
+{
+ int *power_state = (int*)data;
+
+ if(*power_state) {
+ start_thread();
+ RIL_onRequestComplete(t, RIL_E_SUCCESS, NULL, 0);
+ } else {
+ LOGE("%s: power off not implemented", __FUNCTION__);
+ RIL_onRequestComplete(t, RIL_E_GENERIC_FAILURE, NULL, 0);
+ }
+}
+
+void onRequest(int request, void *data, size_t datalen, RIL_Token t)
+{
+ //LOGD("%s: start %d %08X", __FUNCTION__, request, t);
+
+ switch(request) {
+ case RIL_REQUEST_RADIO_POWER:
+ requestPower(t, data, datalen);
+ break;
+ case RIL_REQUEST_BASEBAND_VERSION:
+ requestBasebandVersion(t);
+ break;
+ case RIL_REQUEST_GET_IMSI:
+ requestIMSI(t);
+ break;
+ case RIL_REQUEST_GET_IMEI:
+ requestIMEI(t);
+ break;
+ case RIL_REQUEST_GET_IMEISV:
+ requestIMEISV(t);
+ break;
+ case RIL_REQUEST_OPERATOR:
+ requestOperator(t);
+ break;
+ case RIL_REQUEST_REGISTRATION_STATE:
+ requestRegistrationState(t);
+ break;
+ case RIL_REQUEST_GET_PREFERRED_NETWORK_TYPE:
+ requestGetPreferredNetworkType(t);
+ break;
+ case RIL_REQUEST_SET_PREFERRED_NETWORK_TYPE:
+ requestSetPreferredNetworkType(t, data, datalen);
+ break;
+ case RIL_REQUEST_QUERY_NETWORK_SELECTION_MODE:
+ requestNwSelectionMode(t);
+ break;
+ case RIL_REQUEST_GPRS_REGISTRATION_STATE:
+ requestGPRSRegistrationState(t);
+ break;
+ case RIL_REQUEST_QUERY_AVAILABLE_NETWORKS:
+ requestAvailNetworks(t);
+ break;
+ case RIL_REQUEST_DIAL:
+ requestDial(t, data, datalen);
+ break;
+ case RIL_REQUEST_GET_CURRENT_CALLS:
+ requestGetCurrentCalls(t);
+ break;
+ case RIL_REQUEST_HANGUP:
+ //case RIL_REQUEST_HANGUP_WAITING_OR_BACKGROUND: /* FIXME: We actually don't support background calls */
+ //case RIL_REQUEST_HANGUP_FOREGROUND_RESUME_BACKGROUND: /* FIXME: We actually don't support background calls */
+ requestHangup(t);
+ break;
+ case RIL_REQUEST_ANSWER:
+ requestAnswer(t);
+ break;
+ case RIL_REQUEST_SEND_SMS:
+ requestSendSms(t, data, datalen);
+ break;
+ case RIL_REQUEST_SEND_SMS_EXPECT_MORE:
+ requestSendSms(t, data, datalen);
+ break;
+ case RIL_REQUEST_SMS_ACKNOWLEDGE:
+ requestSmsAcknowledge(t);
+ break;
+ case RIL_REQUEST_GET_SIM_STATUS:
+ requestSimStatus(t);
+ break;
+ case RIL_REQUEST_SIM_IO:
+ requestSimIo(t, data, datalen);
+ break;
+ case RIL_REQUEST_ENTER_SIM_PIN:
+ requestEnterSimPin(t, data, datalen);
+ break;
+ case RIL_REQUEST_QUERY_FACILITY_LOCK:
+ requestQueryFacilityLock(t, data, datalen);
+ break;
+ case RIL_REQUEST_SET_FACILITY_LOCK:
+ requestSetFacilityLock(t, data, datalen);
+ break;
+ case RIL_REQUEST_STK_SEND_TERMINAL_RESPONSE:
+ requestSatSendTerminalResponse(t, data, datalen);
+ break;
+ case RIL_REQUEST_STK_SEND_ENVELOPE_COMMAND:
+ requestSatSendEnvelopeCommand(t, data, datalen);
+ break;
+ case RIL_REQUEST_STK_HANDLE_CALL_SETUP_REQUESTED_FROM_SIM:
+ RIL_onRequestComplete(t, RIL_E_SUCCESS, NULL, 0);
+ break;
+ default:
+ LOGE("Request not implemented: %d\n", request);
+ RIL_onRequestComplete(t, RIL_E_REQUEST_NOT_SUPPORTED, NULL, 0);
+ break;
+ }
+}
+
+RIL_RadioState currentState()
+{
+ return radio.radio_state;
+}
+
+int onSupports(int requestCode)
+{
+ switch(requestCode) {
+ default:
+ return 1;
+ }
+}
+
+void onCancel(RIL_Token t)
+{
+ /* Todo */
+}
+
+const char *getVersion(void)
+{
+ return RIL_VERSION_STRING;
+}
+
+void respondPowerup()
+{
+ /* Update radio state */
+ radio.radio_state = RADIO_STATE_SIM_NOT_READY;
+ RIL_onUnsolicitedResponse(RIL_UNSOL_RESPONSE_RADIO_STATE_CHANGED, NULL, 0);
+
+ /* Send pending IMEI and baseband version requests */
+ if(radio.token_imei) {
+ ipc_client_send_get(IPC_MISC_ME_SN, getRequestId(radio.token_imei));
+ radio.token_imei = 0;
+ }
+
+ if(radio.token_baseband_ver) {
+ ipc_client_send_get(IPC_MISC_ME_VERSION, getRequestId(radio.token_baseband_ver));
+ }
+}
+
+void respondGenPhonRes(struct ipc_message_info *info)
+{
+ struct ipc_gen_phone_res *gen_res = (struct ipc_gen_phone_res*)info->data;
+ unsigned short msg_type = ((gen_res->group << 8) | gen_res->type);
+
+ if(msg_type == IPC_SEC_PIN_STATUS) {
+ respondSecPinStatus(info);
+ } else {
+ LOGD("%s: unhandled generic response for msg %04x", __FUNCTION__, msg_type);
+ }
+}
+
+void onReceive(struct ipc_message_info *info)
+{
+ /* FIXME: This _needs_ to be moved to each individual function. Unsollicited calls do not have a token! */
+ RIL_Token t = getToken(info->aseq);
+
+ switch(IPC_COMMAND(info)) {
+ case IPC_PWR_PHONE_PWR_UP:
+ /* H1 baseband firmware bug workaround: sleep for 25ms to allow for nvram to initialize */
+ usleep(25000);
+ respondPowerup();
+ break;
+ case IPC_MISC_ME_VERSION:
+ respondBasebandVersion(info);
+ break;
+ case IPC_MISC_ME_IMSI:
+ respondIMSI(info);
+ break;
+ case IPC_MISC_ME_SN:
+ respondIMEI(t, info->data, info->length);
+ break;
+ case IPC_MISC_TIME_INFO:
+ respondNitz(info->data, info->length);
+ break;
+ case IPC_NET_CURRENT_PLMN:
+ respondOperator(t, info->data, info->length);
+ break;
+ case IPC_NET_PLMN_LIST:
+ respondAvailNetworks(t, info->data, info->length);
+ break;
+ case IPC_NET_REGIST:
+ respondNetRegist(info);
+ break;
+ case IPC_NET_MODE_SEL:
+ respondModeSel(info);
+ break;
+ case IPC_DISP_ICON_INFO:
+ respondSignalStrength(t, info->data, info->length);
+ break;
+ case IPC_CALL_INCOMING:
+ respondCallIncoming(t, info->data, info->length);
+ break;
+ case IPC_CALL_LIST:
+ respondCallList(t, info->data, info->length);
+ break;
+ case IPC_CALL_STATUS:
+ respondCallStatus(t, info->data, info->length);
+ break;
+ case IPC_SMS_INCOMING_MSG:
+ respondSmsIncoming(t, info->data, info->length);
+ break;
+ case IPC_SEC_PIN_STATUS:
+ respondSimStatusChanged(t, info->data, info->length);
+ break;
+ case IPC_SEC_LOCK_INFO:
+ respondLockInfo(info);
+ break;
+ case IPC_SEC_RSIM_ACCESS:
+ respondSecRsimAccess(t, info->data, info->length);
+ break;
+ case IPC_SEC_PHONE_LOCK:
+ respondSecPhoneLock(info);
+ break;
+ case IPC_SAT_PROACTIVE_CMD:
+ respondSatProactiveCmd(info);
+ break;
+ case IPC_SAT_ENVELOPE_CMD:
+ respondSatEnvelopeCmd(info);
+ break;
+ case IPC_GEN_PHONE_RES:
+ respondGenPhonRes(info);
+ break;
+ default:
+ //LOGD("Unknown msgtype: %04x", info->type);
+ break;
+ }
+}
+
+void ipc_log_handler(const char *message, void *user_data)
+{
+ LOGD("ipc: %s", message);
+}
+
+void *init_loop()
+{
+ struct ipc_message_info resp;
+
+ ipc_client = ipc_client_new(IPC_CLIENT_TYPE_FMT);
+
+ ipc_client_set_log_handler(ipc_client, ipc_log_handler, NULL);
+
+ ipc_client_bootstrap_modem(ipc_client);
+
+ if(ipc_client_open(ipc_client)) {
+ LOGE("%s: failed to open ipc client", __FUNCTION__);
+ return 0;
+ }
+
+ if(ipc_client_power_on(ipc_client)) {
+ LOGE("%s: failed to power on ipc client", __FUNCTION__);
+ return 0;
+ }
+
+ while(1) {
+ ipc_client_recv(ipc_client, &resp);
+
+ onReceive(&resp);
+
+ if(resp.data != NULL)
+ free(resp.data);
+ }
+
+ ipc_client_power_off(ipc_client);
+ ipc_client_close(ipc_client);
+
+ ipc_client_free(ipc_client);
+
+ return 0;
+}
+
+void start_thread()
+{
+ pthread_t thread;
+ pthread_attr_t attr;
+ pthread_attr_init(&attr);
+ pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
+ pthread_create(&thread, &attr, init_loop, NULL);
+}
+
+static const RIL_RadioFunctions radio_ops = {
+ RIL_VERSION,
+ onRequest,
+ currentState,
+ onSupports,
+ onCancel,
+ getVersion
+};
+
+const RIL_RadioFunctions *RIL_Init(const struct RIL_Env *env, int argc, char **argv)
+{
+ memset(&radio, 0, sizeof(radio));
+ radio.radio_state = RADIO_STATE_OFF;
+ radio.token_ps = 0;
+ radio.token_cs = 0;
+
+ rilenv = env;
+
+ return &radio_ops;
+}
+
+int main(int argc, char *argv[])
+{
+ return 0;
+}
+
diff --git a/samsung-ril.h b/samsung-ril.h
new file mode 100644
index 0000000..cf91cb4
--- /dev/null
+++ b/samsung-ril.h
@@ -0,0 +1,99 @@
+#include <telephony/ril.h>
+#include <radio.h>
+
+#define RIL_onRequestComplete(t, e, response, responselen) rilenv->OnRequestComplete(t,e, response, responselen)
+#define RIL_onUnsolicitedResponse(a,b,c) rilenv->OnUnsolicitedResponse(a,b,c)
+#define RIL_requestTimedCallback(a,b,c) rilenv->RequestTimedCallback(a,b,c)
+
+#define ipc_client_send_get(type, request) \
+ ipc_client_send(ipc_client, type, IPC_TYPE_GET, NULL, 0, request)
+
+#define ipc_client_send_set(type, request, data, len) \
+ ipc_client_send(ipc_client, type, IPC_TYPE_SET, data, len, request)
+
+#define ipc_client_send_exec(type, request) \
+ ipc_client_send(ipc_client, type, IPC_TYPE_EXEC, NULL, 0, request)
+
+typedef enum {
+ SIM_ABSENT = 0,
+ SIM_NOT_READY = 1,
+ SIM_READY = 2,
+ SIM_PIN = 3,
+ SIM_PUK = 4,
+ SIM_BLOCKED = 5,
+ SIM_NETWORK_PERSO = 6,
+ SIM_NETWORK_SUBSET_PERSO = 7,
+ SIM_CORPORATE_PERSO = 8,
+ SIM_SERVICE_PROVIDER_PERSO = 9,
+} SIM_Status;
+
+struct radio_state {
+ RIL_RadioState radio_state;
+ RIL_CardState card_state;
+
+ RIL_Token token_imei;
+ RIL_Token token_imeisv;
+
+ RIL_Token token_baseband_ver;
+
+ struct ipc_net_regist netinfo;
+
+ /* SIM status - RIL_REQUEST_GET_SIM_STATUS */
+ SIM_Status sim_status;
+
+ /* Samsung H1 baseband returns bogus request id for NET_REGIST GETs */
+ RIL_Token token_ps, token_cs;
+};
+
+int getRequestId(RIL_Token token);
+RIL_Token getToken(int id);
+
+/* Call */
+void requestCallList(RIL_Token t);
+void requestGetCurrentCalls(RIL_Token t);
+void requestHangup(RIL_Token t);
+void requestAnswer(RIL_Token t);
+void requestDial(RIL_Token t, void *data, size_t datalen);
+void respondCallIncoming(RIL_Token t, void *data, int length);
+void respondCallStatus(RIL_Token t, void *data, int length);
+void respondCallList(RIL_Token t, void *data, int length);
+
+/* Misc */
+void requestBasebandVersion(RIL_Token t);
+void respondBasebandVersion(struct ipc_message_info *request);
+
+/* Net */
+void requestGPRSRegistrationState(RIL_Token t);
+void respondNetRegist(struct ipc_message_info *request);
+void requestGetPreferredNetworkType(RIL_Token t);
+void respondModeSel(struct ipc_message_info *request);
+void requestSetPreferredNetworkType(RIL_Token t, void *data, size_t datalen);
+
+/* SIM */
+void respondSimStatusChanged(RIL_Token t, void *data, int length);
+void requestSimStatus(RIL_Token t);
+void requestSimIo(RIL_Token t, void *data, size_t datalen);
+void respondSecRsimAccess(RIL_Token t, void *data, int length);
+void requestEnterSimPin(RIL_Token t, void *data, size_t datalen);
+void respondSecPinStatus(struct ipc_message_info *request);
+void respondLockInfo(struct ipc_message_info *request);
+void requestQueryFacilityLock(RIL_Token t, void *data, size_t datalen);
+void respondSecPhoneLock(struct ipc_message_info *request);
+void requestSetFacilityLock(RIL_Token t, void *data, size_t datalen);
+
+/* SAT */
+void respondSatProactiveCmd(struct ipc_message_info *request);
+void requestSatSendTerminalResponse(RIL_Token t, void *data, size_t datalen);
+void requestSatSendEnvelopeCommand(RIL_Token t, void *data, size_t datalen);
+void respondSatEnvelopeCmd(struct ipc_message_info *request);
+
+/* SMS */
+void respondSmsIncoming(RIL_Token t, void *data, int length);
+void requestSendSmsEx(RIL_Token t, void *data, size_t datalen, unsigned char hint);
+void requestSendSms(RIL_Token t, void *data, size_t datalen);
+void requestSendSmsExpectMore(RIL_Token t, void *data, size_t datalen);
+void requestSmsAcknowledge(RIL_Token t);
+
+void requestIMSI(RIL_Token t);
+void respondIMSI(struct ipc_message_info *request);
+
diff --git a/sat.c b/sat.c
new file mode 100644
index 0000000..7dce03a
--- /dev/null
+++ b/sat.c
@@ -0,0 +1,137 @@
+#define LOG_TAG "RIL-SAT"
+#include <utils/Log.h>
+
+#include "samsung-ril.h"
+#include "util.h"
+
+extern const struct RIL_Env *rilenv;
+extern struct radio_state radio;
+extern struct ipc_client *ipc_client;
+
+/**
+ * In: IPC_SAT_PROACTIVE_CMD
+ * STK proactive command
+ *
+ * Out: RIL_UNSOL_STK_PROACTIVE_COMMAND
+ */
+void respondSatProactiveCmdIndi(struct ipc_message_info *request)
+{
+ int data_len = (request->length-2);
+ char *hexdata;
+
+ hexdata = (char*)malloc(data_len*2+1);
+
+ bin2hex((unsigned char*)request->data+2, data_len, hexdata);
+
+ RIL_onUnsolicitedResponse(RIL_UNSOL_STK_PROACTIVE_COMMAND, hexdata, sizeof(char*));
+
+ free(hexdata);
+}
+
+/**
+ * In: IPC_SAT_PROACTIVE_CMD RESP
+ * STK proactive command
+ *
+ * Out: RIL_UNSOL_STK_SESSION_END
+ */
+void respondSatProactiveCmdResp(struct ipc_message_info *request)
+{
+ unsigned char sw1, sw2;
+
+ sw1 = ((unsigned char*)request->data)[0];
+ sw2 = ((unsigned char*)request->data)[1];
+
+ if(sw1 == 0x90 && sw2 == 0x00) {
+ RIL_onUnsolicitedResponse(RIL_UNSOL_STK_SESSION_END, NULL, 0);
+ } else {
+ LOGE("%s: unhandled response sw1=%02x sw2=%02x", __FUNCTION__, sw1, sw2);
+ }
+}
+
+/**
+ * Proactive command indi/resp helper function
+ */
+void respondSatProactiveCmd(struct ipc_message_info *request)
+{
+ if(request->type == IPC_TYPE_INDI) {
+ respondSatProactiveCmdIndi(request);
+ } else if(request->type == IPC_TYPE_RESP) {
+ respondSatProactiveCmdResp(request);
+ } else {
+ LOGE("%s: unhandled proactive command response type %d", __FUNCTION__, request->type);
+ }
+}
+
+/**
+ * In: RIL_REQUEST_STK_SEND_TERMINAL_RESPONSE
+ * Requests to send a terminal response to SIM for a received
+ * proactive command
+ *
+ * Out: IPC_SAT_PROACTIVE_CMD GET
+ */
+void requestSatSendTerminalResponse(RIL_Token t, void *data, size_t datalen)
+{
+ unsigned char buf[264];
+ int len = (strlen(data) / 2);
+
+ if(len > 255) {
+ LOGE("%s: data exceeds maximum length", __FUNCTION__);
+ RIL_onRequestComplete(t, RIL_E_GENERIC_FAILURE, NULL, 0);
+ }
+
+ memset(buf, 0, sizeof(buf));
+
+ buf[0] = len;
+ hex2bin(data, strlen(data), &buf[1]);
+
+ ipc_client_send(ipc_client, IPC_SAT_PROACTIVE_CMD, IPC_TYPE_GET, buf, sizeof(buf), getRequestId(t));
+
+ RIL_onRequestComplete(t, RIL_E_SUCCESS, buf, sizeof(char*));
+}
+
+/**
+ * In: RIL_REQUEST_STK_SEND_ENVELOPE_COMMAND
+ * Requests to send a SAT/USAT envelope command to SIM.
+ * The SAT/USAT envelope command refers to 3GPP TS 11.14 and 3GPP TS 31.111
+ *
+ * Out: IPC_SAT_ENVELOPE_CMD EXEC
+ */
+void requestSatSendEnvelopeCommand(RIL_Token t, void *data, size_t datalen)
+{
+ unsigned char buf[264];
+ int len = (strlen(data) / 2);
+
+ if(len > 255) {
+ LOGE("%s: data exceeds maximum length", __FUNCTION__);
+ RIL_onRequestComplete(t, RIL_E_GENERIC_FAILURE, NULL, 0);
+ }
+
+ memset(buf, 0, sizeof(buf));
+
+ buf[0] = len;
+ hex2bin(data, strlen(data), &buf[1]);
+
+ ipc_client_send(ipc_client, IPC_SAT_ENVELOPE_CMD, IPC_TYPE_EXEC, buf, sizeof(buf), getRequestId(t));
+}
+
+/**
+ * In: IPC_SAT_ENVELOPE_CMD EXEC
+ *
+ * Out: RIL_REQUEST_STK_SEND_ENVELOPE_COMMAND
+ * Requests to send a SAT/USAT envelope command to SIM.
+ * The SAT/USAT envelope command refers to 3GPP TS 11.14 and 3GPP TS 31.111
+ */
+void respondSatEnvelopeCmd(struct ipc_message_info *request)
+{
+ int data_len = (request->length-2);
+ char *hexdata;
+
+ hexdata = (char*)malloc(data_len*2+1);
+
+ bin2hex((unsigned char*)request->data+2, data_len, hexdata);
+
+ RIL_onRequestComplete(getToken(request->aseq), RIL_E_SUCCESS, hexdata, sizeof(char*));
+
+ free(hexdata);
+}
+
diff --git a/sim.c b/sim.c
new file mode 100644
index 0000000..4baa379
--- /dev/null
+++ b/sim.c
@@ -0,0 +1,461 @@
+#define LOG_TAG "RIL-SIM"
+#include <utils/Log.h>
+
+#include "samsung-ril.h"
+#include "util.h"
+
+extern const struct RIL_Env *rilenv;
+extern struct radio_state radio;
+extern struct ipc_client *ipc_client;
+
+/**
+ * Update the radio state based on SIM status
+ *
+ * Out: RIL_UNSOL_RESPONSE_RADIO_STATE_CHANGED
+ * Indicate when value of RIL_RadioState has changed
+ * Callee will invoke RIL_RadioStateRequest method on main thread
+ */
+void updateRadioState(SIM_Status status)
+{
+ switch(status) {
+ case SIM_READY:
+ radio.radio_state = RADIO_STATE_SIM_READY;
+ break;
+ case SIM_NOT_READY:
+ radio.radio_state = RADIO_STATE_SIM_NOT_READY;
+ break;
+ case SIM_ABSENT:
+ case SIM_PIN:
+ case SIM_PUK:
+ case SIM_BLOCKED:
+ case SIM_NETWORK_PERSO:
+ case SIM_NETWORK_SUBSET_PERSO:
+ case SIM_CORPORATE_PERSO:
+ case SIM_SERVICE_PROVIDER_PERSO:
+ radio.radio_state = RADIO_STATE_SIM_LOCKED_OR_ABSENT;
+ break;
+ default:
+ radio.radio_state = RADIO_STATE_SIM_NOT_READY;
+ break;
+ }
+
+ RIL_onUnsolicitedResponse(RIL_UNSOL_RESPONSE_RADIO_STATE_CHANGED, NULL, 0);
+}
+
+/**
+ * In: IPC_SEC_PIN_STATUS
+ * Provides SIM initialization/lock status
+ *
+ * Out: RIL_UNSOL_RESPONSE_SIM_STATUS_CHANGED
+ * Indicates that SIM state changes.
+ * Callee will invoke RIL_REQUEST_GET_SIM_STATUS on main thread
+ *
+ * Out: RIL_UNSOL_RESPONSE_RADIO_STATE_CHANGED
+ * Indicate when value of RIL_RadioState has changed
+ * Callee will invoke RIL_RadioStateRequest method on main thread
+ */
+void respondSimStatusChanged(RIL_Token t, void *data, int length)
+{
+ struct ipc_sec_pin_status_noti *pin_status = (struct ipc_sec_pin_status_noti*)data;
+
+ /* Determine SIM status */
+ switch(pin_status->type) {
+ case IPC_SEC_PIN_SIM_INITIALIZING:
+ radio.sim_status = SIM_NOT_READY;
+ break;
+ case IPC_SEC_PIN_SIM_LOCK_SC:
+ switch(pin_status->key) {
+ case IPC_SEC_PIN_SIM_LOCK_SC_PIN1_REQ:
+ radio.sim_status = SIM_PIN;
+ break;
+ case IPC_SEC_PIN_SIM_LOCK_SC_PUK_REQ:
+ radio.sim_status = SIM_PUK;
+ break;
+ case IPC_SEC_PIN_SIM_LOCK_SC_CARD_BLOCKED:
+ radio.sim_status = SIM_BLOCKED;
+ break;
+ default:
+ radio.sim_status = SIM_ABSENT;
+ LOGE("%s: unknown SC substate %d --> setting SIM_ABSENT", __FUNCTION__, pin_status->key);
+ break;
+ }
+ break;
+ case IPC_SEC_PIN_SIM_LOCK_FD:
+ radio.sim_status = SIM_ABSENT;
+ LOGE("%s: FD lock present (unhandled state --> setting SIM_ABSENT)", __FUNCTION__);
+ break;
+ case IPC_SEC_PIN_SIM_LOCK_PN:
+ radio.sim_status = SIM_NETWORK_PERSO;
+ break;
+ case IPC_SEC_PIN_SIM_LOCK_PU:
+ radio.sim_status = SIM_NETWORK_SUBSET_PERSO;
+ break;
+ case IPC_SEC_PIN_SIM_LOCK_PP:
+ radio.sim_status = SIM_SERVICE_PROVIDER_PERSO;
+ break;
+ case IPC_SEC_PIN_SIM_LOCK_PC:
+ radio.sim_status = SIM_CORPORATE_PERSO;
+ break;
+ case IPC_SEC_PIN_SIM_INIT_COMPLETE:
+ radio.sim_status = SIM_READY;
+ break;
+ case IPC_SEC_PIN_SIM_PB_INIT_COMPLETE:
+ /* Ignore phone book init complete */
+ return;
+ case IPC_SEC_PIN_SIM_SIM_LOCK_REQUIRED:
+ case IPC_SEC_PIN_SIM_INSIDE_PF_ERROR:
+ case IPC_SEC_PIN_SIM_CARD_NOT_PRESENT:
+ case IPC_SEC_PIN_SIM_CARD_ERROR:
+ default:
+ /* Catchall for locked, card error and unknown states */
+ radio.sim_status = SIM_ABSENT;
+ break;
+ }
+
+ /* Update radio state based on SIM state */
+ updateRadioState(radio.sim_status);
+
+ RIL_onUnsolicitedResponse(RIL_UNSOL_RESPONSE_SIM_STATUS_CHANGED, NULL, 0);
+}
+
+/**
+ * In: RIL_REQUEST_GET_SIM_STATUS
+ * Requests status of the SIM interface and the SIM card
+ */
+void requestSimStatus(RIL_Token t)
+{
+ static RIL_AppStatus app_status_array[] = {
+ /* SIM_ABSENT = 0 */
+ { RIL_APPTYPE_UNKNOWN, RIL_APPSTATE_UNKNOWN, RIL_PERSOSUBSTATE_UNKNOWN,
+ NULL, NULL, 0, RIL_PINSTATE_UNKNOWN, RIL_PINSTATE_UNKNOWN },
+ /* SIM_NOT_READY = 1 */
+ { RIL_APPTYPE_SIM, RIL_APPSTATE_DETECTED, RIL_PERSOSUBSTATE_UNKNOWN,
+ NULL, NULL, 0, RIL_PINSTATE_UNKNOWN, RIL_PINSTATE_UNKNOWN },
+ /* SIM_READY = 2 */
+ { RIL_APPTYPE_SIM, RIL_APPSTATE_READY, RIL_PERSOSUBSTATE_READY,
+ NULL, NULL, 0, RIL_PINSTATE_UNKNOWN, RIL_PINSTATE_UNKNOWN },
+ /* SIM_PIN = 3 */
+ { RIL_APPTYPE_SIM, RIL_APPSTATE_PIN, RIL_PERSOSUBSTATE_UNKNOWN,
+ NULL, NULL, 0, RIL_PINSTATE_ENABLED_NOT_VERIFIED, RIL_PINSTATE_UNKNOWN },
+ /* SIM_PUK = 4 */
+ { RIL_APPTYPE_SIM, RIL_APPSTATE_PUK, RIL_PERSOSUBSTATE_UNKNOWN,
+ NULL, NULL, 0, RIL_PINSTATE_ENABLED_BLOCKED, RIL_PINSTATE_UNKNOWN },
+ /* SIM_BLOCKED = 4 */
+ { RIL_APPTYPE_SIM, RIL_APPSTATE_PUK, RIL_PERSOSUBSTATE_UNKNOWN,
+ NULL, NULL, 0, RIL_PINSTATE_ENABLED_PERM_BLOCKED, RIL_PINSTATE_UNKNOWN },
+ /* SIM_NETWORK_PERSO = 6 */
+ { RIL_APPTYPE_SIM, RIL_APPSTATE_SUBSCRIPTION_PERSO, RIL_PERSOSUBSTATE_SIM_NETWORK,
+ NULL, NULL, 0, RIL_PINSTATE_ENABLED_NOT_VERIFIED, RIL_PINSTATE_UNKNOWN },
+ /* SIM_NETWORK_SUBSET_PERSO = 7 */
+ { RIL_APPTYPE_SIM, RIL_APPSTATE_SUBSCRIPTION_PERSO, RIL_PERSOSUBSTATE_SIM_NETWORK_SUBSET,
+ NULL, NULL, 0, RIL_PINSTATE_ENABLED_NOT_VERIFIED, RIL_PINSTATE_UNKNOWN },
+ /* SIM_CORPORATE_PERSO = 8 */
+ { RIL_APPTYPE_SIM, RIL_APPSTATE_SUBSCRIPTION_PERSO, RIL_PERSOSUBSTATE_SIM_CORPORATE,
+ NULL, NULL, 0, RIL_PINSTATE_ENABLED_NOT_VERIFIED, RIL_PINSTATE_UNKNOWN },
+ /* SIM_SERVICE_PROVIDER_PERSO = 9 */
+ { RIL_APPTYPE_SIM, RIL_APPSTATE_SUBSCRIPTION_PERSO, RIL_PERSOSUBSTATE_SIM_SERVICE_PROVIDER,
+ NULL, NULL, 0, RIL_PINSTATE_ENABLED_NOT_VERIFIED, RIL_PINSTATE_UNKNOWN },
+ };
+
+ int i, num_applications;
+ RIL_CardState card_state;
+ RIL_CardStatus card_status;
+
+ /* Card is assumed to be present if not explicitly absent */
+ if(radio.sim_status == SIM_ABSENT) {
+ card_state = RIL_CARDSTATE_ABSENT;
+ } else {
+ card_state = RIL_CARDSTATE_PRESENT;
+ }
+
+ /* Fill in struct */
+ card_status.card_state = card_state;
+ card_status.universal_pin_state = RIL_PINSTATE_UNKNOWN;
+ card_status.gsm_umts_subscription_app_index = RIL_CARD_MAX_APPS;
+ card_status.cdma_subscription_app_index = RIL_CARD_MAX_APPS;
+ card_status.num_applications = 0;
+
+ /* Initialize apps */
+ for (i = 0; i < RIL_CARD_MAX_APPS; i++) {
+ card_status.applications[i] = app_status_array[0];
+ }
+
+ /* If a card is present, add the gsm/umts application */
+ if(card_status.card_state == RIL_CARDSTATE_PRESENT) {
+ card_status.gsm_umts_subscription_app_index = 0;
+ card_status.num_applications = 1;
+ card_status.applications[0] = app_status_array[radio.sim_status];
+
+ /* FIXME: if USIM, set apptype */
+ //card_status.applications[0] = RIL_APPTYPE_USIM
+ }
+
+ RIL_onRequestComplete(t, RIL_E_SUCCESS, &card_status, sizeof(card_status));
+}
+
+/**
+ * In: RIL_REQUEST_SIM_IO
+ * Request SIM I/O operation.
+ * This is similar to the TS 27.007 "restricted SIM" operation
+ * where it assumes all of the EF selection will be done by the
+ * callee.
+ *
+ * Out: IPC_SEC_RSIM_ACCESS
+ * Performs a restricted SIM read operation
+ */
+void requestSimIo(RIL_Token t, void *data, size_t datalen)
+{
+ const RIL_SIM_IO *sim_io;
+ unsigned char message[262];
+ struct ipc_sec_rsim_access_request *rsim_data;
+
+ unsigned char *rsim_payload;
+ int payload_length;
+
+ sim_io = (const RIL_SIM_IO*)data;
+ rsim_payload = message + sizeof(*rsim_data);
+
+ /* Set up RSIM header */
+ rsim_data = (struct ipc_sec_rsim_access_request*)message;
+ rsim_data->command = sim_io->command;
+ rsim_data->fileid = sim_io->fileid;
+ rsim_data->p1 = sim_io->p1;
+ rsim_data->p2 = sim_io->p2;
+ rsim_data->p3 = sim_io->p3;
+
+ /* Add payload if present */
+ if(sim_io->data) {
+ payload_length = (2 * strlen(sim_io->data));
+
+ if(sizeof(*rsim_data) + payload_length > sizeof(message))
+ return;
+
+ hex2bin(sim_io->data, strlen(sim_io->data), rsim_payload);
+ }
+
+ ipc_client_send(ipc_client, IPC_SEC_RSIM_ACCESS, IPC_TYPE_GET, (unsigned char*)&message, sizeof(message), getRequestId(t));
+}
+
+/**
+ * In: IPC_SEC_RSIM_ACCESS
+ * Provides restricted SIM read operation result
+ *
+ * Out: RIL_REQUEST_SIM_IO
+ * Request SIM I/O operation.
+ * This is similar to the TS 27.007 "restricted SIM" operation
+ * where it assumes all of the EF selection will be done by the
+ * callee.
+ */
+void respondSecRsimAccess(RIL_Token t, void *data, int length)
+{
+ struct ipc_sec_rsim_access_response *rsim_resp = (struct ipc_sec_rsim_access_response*)data;
+ const unsigned char *data_ptr = ((unsigned char*)data + sizeof(*rsim_resp));
+ char *sim_resp;
+ RIL_SIM_IO_Response response;
+
+ response.sw1 = rsim_resp->sw1;
+ response.sw2 = rsim_resp->sw2;
+
+ if(rsim_resp->len) {
+ sim_resp = (char*)malloc(rsim_resp->len * 2 + 1);
+ bin2hex(data_ptr, rsim_resp->len, sim_resp);
+ response.simResponse = sim_resp;
+ } else {
+ response.simResponse = malloc(1);
+ response.simResponse[0] = '\0';
+ }
+
+ RIL_onRequestComplete(t, RIL_E_SUCCESS, &response, sizeof(response));
+
+ free(response.simResponse);
+}
+
+/**
+ * In: RIL_REQUEST_GET_IMSI
+ * Get the SIM IMSI
+ * Only valid when radio state is "RADIO_STATE_SIM_READY"
+ *
+ * Out: IPC_MISC_ME_IMSI
+ * Requests ME's IMSI
+ */
+void requestIMSI(RIL_Token t)
+{
+ ipc_client_send_get(IPC_MISC_ME_IMSI, getRequestId(t));
+}
+
+/**
+ * In: IPC_MISC_ME_IMSI
+ * Provides ME's IMSI
+ *
+ * Out: RIL_REQUEST_GET_IMSI
+ * Get the SIM IMSI
+ * Only valid when radio state is "RADIO_STATE_SIM_READY"
+ */
+void respondIMSI(struct ipc_message_info *request)
+{
+ unsigned char *imsi_length;
+ char *imsi;
+
+ if(request->length < 1) {
+ LOGE("%s: zero data length", __FUNCTION__);
+ RIL_onRequestComplete(getToken(request->aseq), RIL_E_GENERIC_FAILURE, NULL, 0);
+ return;
+ }
+
+ imsi_length = (unsigned char*)request->data;
+
+ if(((int)request->length) < *imsi_length + 1) {
+ LOGE("%s: missing IMSI data", __FUNCTION__);
+ RIL_onRequestComplete(getToken(request->aseq), RIL_E_GENERIC_FAILURE, NULL, 0);
+ return;
+ }
+
+ /* Copy IMSI */
+ imsi = (char*)malloc(*imsi_length+1);
+ memcpy(imsi, ((unsigned char*)request->data)+1, *imsi_length);
+ imsi[*imsi_length] = '\0';
+
+ RIL_onRequestComplete(getToken(request->aseq), RIL_E_SUCCESS, imsi, *imsi_length+1);
+}
+
+/**
+ * In: RIL_REQUEST_ENTER_SIM_PIN
+ * Supplies SIM PIN. Only called if RIL_CardStatus has RIL_APPSTATE_PIN state
+ *
+ * Out: IPC_SEC_PIN_STATUS SET
+ * Attempts to unlock SIM PIN1
+ *
+ * Out: IPC_SEC_LOCK_INFO
+ * Retrieves PIN1 lock status
+ */
+void requestEnterSimPin(RIL_Token t, void *data, size_t datalen)
+{
+ struct ipc_sec_pin_status_set pin_status;
+ char *pin = ((char**)data)[0];
+ unsigned char buf[9];
+
+ /* 1. Send PIN */
+ if(strlen(data) > 16) {
+ LOGE("%s: pin exceeds maximum length", __FUNCTION__);
+ RIL_onRequestComplete(t, RIL_E_GENERIC_FAILURE, NULL, 0);
+ }
+
+ memset(&pin_status, 0, sizeof(pin_status));
+
+ pin_status.type = IPC_SEC_PIN_TYPE_PIN1;
+ pin_status.length1 = strlen(pin);
+ memcpy(pin_status.pin1, pin, strlen(pin));
+
+ ipc_client_send_set(IPC_SEC_PIN_STATUS, getRequestId(t), (unsigned char*)&pin_status, sizeof(pin_status));
+
+ /* 2. Get lock status */
+ memset(buf, 0, sizeof(buf));
+ buf[0] = 1;
+ buf[1] = IPC_SEC_PIN_TYPE_PIN1;
+
+ ipc_client_send(ipc_client, IPC_SEC_LOCK_INFO, IPC_TYPE_GET, buf, sizeof(buf), getRequestId(t));
+}
+
+/**
+ * In: IPC_GEN_PHONE_RES
+ * Provides result of IPC_SEC_PIN_STATUS SET
+ *
+ * Out: RIL_REQUEST_ENTER_SIM_PIN
+ * Returns PIN SIM unlock result
+ */
+void respondSecPinStatus(struct ipc_message_info *request)
+{
+ struct ipc_gen_phone_res *gen_res = (struct ipc_gen_phone_res*)request->data;
+ int attempts = -1;
+
+ if(gen_res->code == 0x0010) {
+ RIL_onRequestComplete(getToken(request->aseq), RIL_E_PASSWORD_INCORRECT, &attempts, sizeof(int*));
+ } else if(gen_res->code == 0x8000) {
+ RIL_onRequestComplete(getToken(request->aseq), RIL_E_SUCCESS, &attempts, sizeof(int*));
+ } else {
+ LOGE("%s: unhandled code %04x", __FUNCTION__, gen_res->code);
+ }
+}
+
+/**
+ * In: IPC_SEC_LOCK_INFO
+ * Provides number of retries left for a lock type
+ */
+void respondLockInfo(struct ipc_message_info *request)
+{
+ /*
+ * FIXME: solid way of handling lockinfo and sim unlock response together
+ * so we can return the number of attempts left in respondSecPinStatus
+ */
+ int attempts;
+ struct ipc_sec_lock_info_response *lock_info = (struct ipc_sec_lock_info_response*)request->data;
+
+ if(lock_info->type == IPC_SEC_PIN_TYPE_PIN1) {
+ attempts = lock_info->attempts;
+ LOGD("%s: PIN1 %d attempts left", __FUNCTION__, attempts);
+ } else {
+ LOGE("%s: unhandled lock type %d", __FUNCTION__, lock_info->type);
+ }
+}
+
+/**
+ * In: RIL_REQUEST_QUERY_FACILITY_LOCK
+ * Query the status of a facility lock state
+ *
+ * Out: IPC_SEC_PHONE_LOCK GET
+ */
+void requestQueryFacilityLock(RIL_Token t, void *data, size_t datalen)
+{
+ unsigned char lock_type;
+ char *facility = ((char**)data)[0];
+
+ if(!strcmp(facility, "SC")) {
+ lock_type = IPC_SEC_PIN_SIM_LOCK_SC;
+ } else if(!strcmp(facility, "FD")) {
+ lock_type = IPC_SEC_PIN_SIM_LOCK_FD;
+ } else {
+ LOGE("%s: unsupported facility: %s", __FUNCTION__, facility);
+ RIL_onRequestComplete(t, RIL_E_GENERIC_FAILURE, NULL, 0);
+ }
+
+ ipc_client_send(ipc_client, IPC_SEC_PHONE_LOCK, IPC_TYPE_GET, &lock_type, sizeof(lock_type), getRequestId(t));
+}
+
+/**
+ * In: IPC_SEC_PHONE_LOCK
+ *
+ * Out: RIL_REQUEST_QUERY_FACILITY_LOCK
+ * Query the status of a facility lock state
+ */
+void respondSecPhoneLock(struct ipc_message_info *request)
+{
+ int status;
+ struct ipc_sec_phone_lock_response *lock = (struct ipc_sec_phone_lock_response*)request->data;
+
+ status = lock->status;
+
+ RIL_onRequestComplete(getToken(request->aseq), RIL_E_SUCCESS, &status, sizeof(int*));
+}
+
+/**
+ * In: RIL_REQUEST_SET_FACILITY_LOCK
+ * Enable/disable one facility lock
+ *
+ * Out: IPC_SEC_PHONE_LOCK SET
+ */
+void requestSetFacilityLock(RIL_Token t, void *data, size_t datalen)
+{
+ unsigned char lock_type;
+ char *facility = ((char**)data)[0];
+
+ if(!strcmp(facility, "SC")) {
+ lock_type = IPC_SEC_PIN_SIM_LOCK_SC;
+ } else if(!strcmp(facility, "FD")) {
+ lock_type = IPC_SEC_PIN_SIM_LOCK_FD;
+ } else {
+ LOGE("%s: unsupported facility: %s", __FUNCTION__, facility);
+ RIL_onRequestComplete(t, RIL_E_GENERIC_FAILURE, NULL, 0);
+ }
+
+ ipc_client_send(ipc_client, IPC_SEC_PHONE_LOCK, IPC_TYPE_GET, &lock_type, sizeof(lock_type), getRequestId(t));
+}
diff --git a/sms.c b/sms.c
new file mode 100644
index 0000000..0405649
--- /dev/null
+++ b/sms.c
@@ -0,0 +1,130 @@
+#define LOG_TAG "RIL-SMS"
+#include <utils/Log.h>
+
+#include "samsung-ril.h"
+#include "util.h"
+
+extern const struct RIL_Env *rilenv;
+extern struct radio_state radio;
+extern struct ipc_client *ipc_client;
+
+void respondSmsIncoming(RIL_Token t, void *data, int length)
+{
+ struct ipc_sms_incoming_msg *info = (struct ipc_sms_incoming_msg*)data;
+ unsigned char *pdu = ((unsigned char*)data+sizeof(struct ipc_sms_incoming_msg));
+
+ /**
+ * H1 libtelplugin seems to provide the SMSC address length
+ * instead of the number of octects used for the SMSC info struct
+ */
+ pdu[0] = (pdu[0] >> 1) + (pdu[0] & 0x01) + 1;
+
+ int resp_length = length * 2 + 1;
+ char *resp = (char*)malloc(resp_length);
+
+ bin2hex(pdu, length, resp);
+
+ if(info->type == IPC_SMS_TYPE_POINT_TO_POINT) {
+ RIL_onUnsolicitedResponse(RIL_UNSOL_RESPONSE_NEW_SMS, resp, resp_length);
+ } else if(info->type == IPC_SMS_TYPE_STATUS_REPORT) {
+ RIL_onUnsolicitedResponse(RIL_UNSOL_RESPONSE_NEW_SMS_STATUS_REPORT, resp, resp_length);
+ } else {
+ LOGE("%s: Unknown message type", __FUNCTION__);
+ }
+
+ free(resp);
+}
+
+/**
+ * Helper function to send a single SMS
+ * Optionally notifying the network that
+ * additional messages are to be expected
+ */
+void requestSendSmsEx(RIL_Token t, void *data, size_t datalen, unsigned char hint)
+{
+ int sc_length, data_length, length;
+ struct ipc_sms_send_msg *msg;
+ unsigned char *p, *buf;
+ const char **request = (const char**)data;
+
+ /**
+ * If the SC is not provided we need to specify length 0 -> 1 zero byte
+ */
+ sc_length = (request[0] != NULL) ? (strlen(request[0]) / 2) : 1;
+ data_length = (strlen(request[1]) / 2);
+
+ length = sizeof(struct ipc_sms_send_msg) + sc_length + data_length;
+
+ buf = (unsigned char*)malloc(length);
+ memset(buf, 0, length);
+ p = buf;
+
+ /* First, setup the header required by IPC */
+ msg = (struct ipc_sms_send_msg*)p;
+ msg->hint = hint;
+ msg->length = sc_length + data_length;
+
+ p += sizeof(struct ipc_sms_send_msg);
+
+ /* Add SC data */
+ if(sc_length > 1) {
+ hex2bin(request[0], strlen(request[0]), p);
+ } else {
+ *p = 0x00;
+ }
+
+ p += sc_length;
+
+ /* Add SMS PDU data */
+ hex2bin(request[1], strlen(request[1]), p);
+
+ /* FIXME: ipc_sms_send_msg(buf, length, getRequestId(t)); */
+ LOGE("%s: missing impl", __FUNCTION__);
+
+ /* FIXME: Move to baseband response handler */
+ RIL_onRequestComplete(t, RIL_E_SUCCESS, NULL, 0);
+
+ free(buf);
+}
+
+/**
+ * In: RIL_REQUEST_SEND_SMS
+ * Send an SMS message
+ *
+ * Out: IPC_SMS_SEND_MSG
+ */
+void requestSendSms(RIL_Token t, void *data, size_t datalen)
+{
+ requestSendSmsEx(t, data, datalen, IPC_SMS_MSG_SINGLE);
+}
+
+/**
+ * In: RIL_REQUEST_SEND_SMS_EXPECT_MORE
+ * Send an SMS message. Identical to RIL_REQUEST_SEND_SMS,
+ * except that more messages are expected to be sent soon. If possible,
+ * keep SMS relay protocol link open (eg TS 27.005 AT+CMMS command)
+ *
+ * Out: IPC_SMS_SEND_MSG
+ */
+void requestSendSmsExpectMore(RIL_Token t, void *data, size_t datalen)
+{
+ requestSendSmsEx(t, data, datalen, IPC_SMS_MSG_MULTIPLE);
+}
+
+/**
+ * In: RIL_REQUEST_SMS_ACKNOWLEDGE
+ * Acknowledge successful or failed receipt of SMS previously indicated
+ * via RIL_UNSOL_RESPONSE_NEW_SMS
+ *
+ * Out: IPC_SMS_DELIVER_REPORT
+ * Sends a SMS delivery report
+ */
+void requestSmsAcknowledge(RIL_Token t)
+{
+ /* FIXME ipc_sms_deliver_report(getRequestId(t)); */
+ LOGE("%s: missing impl", __FUNCTION__);
+
+ /* FIXME: Move to baseband response handler */
+ RIL_onRequestComplete(t, RIL_E_SUCCESS, NULL, 0);
+}
+
diff --git a/util.c b/util.c
new file mode 100644
index 0000000..3e33e0f
--- /dev/null
+++ b/util.c
@@ -0,0 +1,136 @@
+#include <stdio.h>
+#include <string.h>
+
+#define LOG_TAG "RIL-UTIL"
+#include <utils/Log.h>
+
+/**
+ * Converts a hexidecimal string to binary
+ */
+void hex2bin(const char *data, int length, unsigned char *buf)
+{
+ int i = 0;
+ char b = 0;
+ unsigned char *p = buf;
+
+ length ^= 0x01;
+
+ while(i < length) {
+ if(data[i] - '0' < 10)
+ b = data[i++] - '0';
+ else if(data[i] - 'a' < 7)
+ b = data[i++] - 'a' + 10;
+ else if(data[i] - 'A' < 7)
+ b = data[i++] - 'A' + 10;
+
+ b = (b << 4);
+
+ if(data[i] - '0' < 10)
+ b |= data[i++] - '0';
+ else if(data[i] - 'a' < 7)
+ b |= data[i++] - 'a' + 10;
+ else if(data[i] - 'A' < 7)
+ b |= data[i++] - 'A' + 10;
+
+ *p++ = b;
+ }
+}
+
+/**
+ * Converts binary data to a hexidecimal string
+ */
+void bin2hex(const unsigned char *data, int length, char *buf)
+{
+ int i;
+ char b;
+ char *p = buf;
+
+ for(i = 0; i < length; i++) {
+ b = (data[i] >> 4 & 0x0f);
+ b += (b < 10) ? '0' : ('a' - 10);
+ *p++ = b;
+
+ b = (data[i] & 0x0f);
+ b += (b < 10) ? '0' : ('a' - 10);
+ *p++ = b;
+ }
+
+ *p = '\0';
+}
+
+/**
+ * Converts IPC network registration status to Android RIL format
+ */
+unsigned char registatus_ipc2ril(unsigned char status)
+{
+ switch(status) {
+ case 1:
+ return 0;
+ case 2:
+ return 1;
+ case 3:
+ return 2;
+ case 4:
+ return 13;
+ case 5:
+ return 14;
+ case 6:
+ return 5;
+ default:
+ LOGE("%s: invalid status %d", __FUNCTION__, status);
+ return 255;
+ }
+}
+
+/**
+ * Converts IPC network access technology to Android RIL format
+ */
+unsigned char act_ipc2ril(unsigned char act)
+{
+ switch(act) {
+ case 1:
+ case 2:
+ return 1;
+ case 3:
+ return 2;
+ case 4:
+ return 3;
+ default:
+ return 0;
+ }
+}
+
+/**
+ * Converts IPC preferred network type to Android RIL format
+ */
+unsigned char modesel_ipc2ril(unsigned char mode)
+{
+ switch(mode) {
+ case 0:
+ return 7;
+ case 1:
+ case 3:
+ return 1;
+ case 2:
+ case 4:
+ return 2;
+ default:
+ return 255;
+ }
+}
+
+/**
+ * Converts Android RIL preferred network type to IPC format
+ */
+unsigned char modesel_ril2ipc(unsigned char mode)
+{
+ switch(mode) {
+ case 1:
+ return 2;
+ case 2:
+ return 3;
+ default:
+ return 1;
+ }
+}
+
diff --git a/util.h b/util.h
new file mode 100644
index 0000000..820c1f5
--- /dev/null
+++ b/util.h
@@ -0,0 +1,8 @@
+void bin2hex(const unsigned char *data, int length, char *buf);
+void hex2bin(const char *data, int length, unsigned char *buf);
+
+unsigned char registatus_ipc2ril(unsigned char status);
+unsigned char act_ipc2ril(unsigned char act);
+unsigned char modesel_ipc2ril(unsigned char mode);
+unsigned char modesel_ril2ipc(unsigned char mode);
+