diff options
-rw-r--r-- | Android.mk | 44 | ||||
-rw-r--r-- | call.c | 184 | ||||
-rw-r--r-- | misc.c | 29 | ||||
-rw-r--r-- | net.c | 84 | ||||
-rw-r--r-- | samsung-ril.c | 539 | ||||
-rw-r--r-- | samsung-ril.h | 99 | ||||
-rw-r--r-- | sat.c | 137 | ||||
-rw-r--r-- | sim.c | 461 | ||||
-rw-r--r-- | sms.c | 130 | ||||
-rw-r--r-- | util.c | 136 | ||||
-rw-r--r-- | util.h | 8 |
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 @@ -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); +} @@ -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)); +} + @@ -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); + @@ -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); +} + @@ -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)); +} @@ -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); +} + @@ -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; + } +} + @@ -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); + |