diff options
Diffstat (limited to 'samsung-ril.c')
-rw-r--r-- | samsung-ril.c | 1812 |
1 files changed, 1254 insertions, 558 deletions
diff --git a/samsung-ril.c b/samsung-ril.c index 245685e..43784a7 100644 --- a/samsung-ril.c +++ b/samsung-ril.c @@ -2,7 +2,7 @@ * This file is part of Samsung-RIL. * * Copyright (C) 2010-2011 Joerie de Gram <j.de.gram@gmail.com> - * Copyright (C) 2011-2013 Paul Kocialkowski <contact@paulk.fr> + * Copyright (C) 2011-2014 Paul Kocialkowski <contact@paulk.fr> * * Samsung-RIL is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -18,805 +18,1501 @@ * along with Samsung-RIL. If not, see <http://www.gnu.org/licenses/>. */ +#include <stdlib.h> +#include <ctype.h> + #define LOG_TAG "RIL" -#include "samsung-ril.h" -#include "util.h" +#include <utils/Log.h> +#include <telephony/ril.h> + +#include <samsung-ril.h> +#include <utils.h> /* * RIL data */ -struct ril_data ril_data; +struct ril_data *ril_data = NULL; /* - * RIL requests + * RIL clients */ -int ril_request_id_get(void) -{ - ril_data.request_id++; - ril_data.request_id %= 0xff; +struct ril_client *ril_clients[] = { + &ipc_fmt_client, + &ipc_rfs_client, + &srs_client, +}; - return ril_data.request_id; -} +unsigned int ril_clients_count = sizeof(ril_clients) / + sizeof(struct ril_client *); + +struct ipc_dispatch_handler ipc_fmt_dispatch_handlers[] = { + /* Power */ + { + .command = IPC_PWR_PHONE_PWR_UP, + .handler = ipc_pwr_phone_pwr_up, + }, + { + .command = IPC_PWR_PHONE_RESET, + .handler = ipc_pwr_phone_reset, + }, + { + .command = IPC_PWR_PHONE_STATE, + .handler = ipc_pwr_phone_state, + }, + /* Call */ + { + .command = IPC_CALL_INCOMING, + .handler = ipc_call_incoming, + }, + { + .command = IPC_CALL_STATUS, + .handler = ipc_call_status, + }, + { + .command = IPC_CALL_LIST, + .handler = ipc_call_list, + }, + { + .command = IPC_CALL_BURST_DTMF, + .handler = ipc_call_burst_dtmf, + }, + /* SMS */ + { + .command = IPC_SMS_SEND_MSG, + .handler = ipc_sms_send_msg, + }, + { + .command = IPC_SMS_INCOMING_MSG, + .handler = ipc_sms_incoming_msg, + }, + { + .command = IPC_SMS_SAVE_MSG, + .handler = ipc_sms_save_msg, + }, + { + .command = IPC_SMS_DEL_MSG, + .handler = ipc_sms_del_msg, + }, + { + .command = IPC_SMS_DELIVER_REPORT, + .handler = ipc_sms_deliver_report, + }, + { + .command = IPC_SMS_SVC_CENTER_ADDR, + .handler = ipc_sms_svc_center_addr, + }, + /* SIM */ + { + .command = IPC_SEC_PIN_STATUS, + .handler = ipc_sec_pin_status, + }, + { + .command = IPC_SEC_PHONE_LOCK, + .handler = ipc_sec_phone_lock, + }, + { + .command = IPC_SEC_RSIM_ACCESS, + .handler = ipc_sec_rsim_access, + }, + { + .command = IPC_SEC_SIM_ICC_TYPE, + .handler = ipc_sec_sim_icc_type, + }, + { + .command = IPC_SEC_LOCK_INFOMATION, + .handler = ipc_sec_lock_infomation, + }, + /* Network */ + { + .command = IPC_DISP_ICON_INFO, + .handler = ipc_disp_icon_info, + }, + { + .command = IPC_DISP_RSSI_INFO, + .handler = ipc_disp_rssi_info, + }, + { + .command = IPC_NET_PLMN_SEL, + .handler = ipc_net_plmn_sel, + }, + { + .command = IPC_NET_SERVING_NETWORK, + .handler = ipc_net_serving_network, + }, + { + .command = IPC_NET_PLMN_LIST, + .handler = ipc_net_plmn_list, + }, + { + .command = IPC_NET_REGIST, + .handler = ipc_net_regist, + }, + { + .command = IPC_NET_MODE_SEL, + .handler = ipc_net_mode_sel, + }, + /* Misc */ + { + .command = IPC_MISC_ME_VERSION, + .handler = ipc_misc_me_version, + }, + { + .command = IPC_MISC_ME_IMSI, + .handler = ipc_misc_me_imsi, + }, + { + .command = IPC_MISC_ME_SN, + .handler = ipc_misc_me_sn, + }, + { + .command = IPC_MISC_TIME_INFO, + .handler = ipc_misc_time_info, + }, + /* OEM */ + { + .command = IPC_SVC_DISPLAY_SCREEN, + .handler = ipc_svc_display_screen, + }, + /* Data */ + { + .command = IPC_GPRS_PS, + .handler = ipc_gprs_ps, + }, + { + .command = IPC_GPRS_PDP_CONTEXT, + .handler = ipc_gprs_pdp_context, + }, + { + .command = IPC_GPRS_IP_CONFIGURATION, + .handler = ipc_gprs_ip_configuration, + }, + { + .command = IPC_GPRS_HSDPA_STATUS, + .handler = ipc_gprs_hsdpa_status, + }, + { + .command = IPC_GPRS_CALL_STATUS, + .handler = ipc_gprs_call_status, + }, + /* GEN */ + { + .command = IPC_GEN_PHONE_RES, + .handler = ipc_gen_phone_res, + }, +}; + +unsigned int ipc_fmt_dispatch_handlers_count = sizeof(ipc_fmt_dispatch_handlers) / + sizeof(struct ipc_dispatch_handler); + +struct ipc_dispatch_handler ipc_rfs_dispatch_handlers[] = { + { + .command = IPC_RFS_NV_READ_ITEM, + .handler = ipc_rfs_nv_read_item, + }, + { + .command = IPC_RFS_NV_WRITE_ITEM, + .handler = ipc_rfs_nv_write_item, + }, +}; + +unsigned int ipc_rfs_dispatch_handlers_count = sizeof(ipc_rfs_dispatch_handlers) / + sizeof(struct ipc_dispatch_handler); + +struct srs_dispatch_handler srs_dispatch_handlers[] = { + { + .command = SRS_CONTROL_PING, + .handler = srs_control_ping, + }, + { + .command = SRS_SND_SET_CALL_VOLUME, + .handler = srs_snd_set_call_volume, + }, + { + .command = SRS_SND_SET_CALL_AUDIO_PATH, + .handler = srs_snd_set_call_audio_path, + }, + { + .command = SRS_SND_SET_CALL_CLOCK_SYNC, + .handler = srs_snd_set_call_clock_sync, + }, +}; + +unsigned int srs_dispatch_handlers_count = sizeof(srs_dispatch_handlers) / + sizeof(struct srs_dispatch_handler); + +/* + * RIL request + */ + +struct ril_request_handler ril_request_handlers[] = { + /* Power */ + { + .request = RIL_REQUEST_RADIO_POWER, + .handler = ril_request_radio_power, + }, + /* Call */ + { + .request = RIL_REQUEST_DIAL, + .handler = ril_request_dial, + }, + { + .request = RIL_REQUEST_HANGUP, + .handler = ril_request_hangup, + }, + { + .request = RIL_REQUEST_HANGUP_WAITING_OR_BACKGROUND, + .handler = ril_request_hangup, + }, + { + .request = RIL_REQUEST_HANGUP_FOREGROUND_RESUME_BACKGROUND, + .handler = ril_request_hangup, + }, + { + .request = RIL_REQUEST_ANSWER, + .handler = ril_request_answer, + }, + { + .request = RIL_REQUEST_LAST_CALL_FAIL_CAUSE, + .handler = ril_request_last_call_fail_cause, + }, + { + .request = RIL_REQUEST_GET_CURRENT_CALLS, + .handler = ril_request_get_current_calls, + }, + { + .request = RIL_REQUEST_DTMF, + .handler = ril_request_dtmf, + }, + { + .request = RIL_REQUEST_DTMF_START, + .handler = ril_request_dtmf_start, + }, + { + .request = RIL_REQUEST_DTMF_STOP, + .handler = ril_request_dtmf_stop, + }, + /* SMS */ + { + .request = RIL_REQUEST_SEND_SMS, + .handler = ril_request_send_sms, + }, + { + .request = RIL_REQUEST_SEND_SMS_EXPECT_MORE, + .handler = ril_request_send_sms, + }, + { + .request = RIL_REQUEST_WRITE_SMS_TO_SIM, + .handler = ril_request_write_sms_to_sim, + }, + { + .request = RIL_REQUEST_DELETE_SMS_ON_SIM, + .handler = ril_request_delete_sms_on_sim, + }, + { + .request = RIL_REQUEST_SMS_ACKNOWLEDGE, + .handler = ril_request_sms_acknowledge, + }, + /* SIM */ + { + .request = RIL_REQUEST_GET_SIM_STATUS, + .handler = ril_request_get_sim_status, + }, + { + .request = RIL_REQUEST_QUERY_FACILITY_LOCK, + .handler = ril_request_query_facility_lock, + }, + { + .request = RIL_REQUEST_SET_FACILITY_LOCK, + .handler = ril_request_set_facility_lock, + }, + { + .request = RIL_REQUEST_ENTER_SIM_PIN, + .handler = ril_request_enter_sim_pin, + }, + { + .request = RIL_REQUEST_ENTER_SIM_PUK, + .handler = ril_request_enter_sim_puk, + }, + { + .request = RIL_REQUEST_ENTER_SIM_PIN2, + .handler = ril_request_enter_sim_pin2, + }, + { + .request = RIL_REQUEST_ENTER_SIM_PUK2, + .handler = ril_request_enter_sim_puk2, + }, + { + .request = RIL_REQUEST_CHANGE_SIM_PIN, + .handler = ril_request_change_sim_pin, + }, + { + .request = RIL_REQUEST_CHANGE_SIM_PIN2, + .handler = ril_request_change_sim_pin2, + }, + { + .request = RIL_REQUEST_SIM_IO, + .handler = ril_request_sim_io, + }, + /* Network */ + { + .request = RIL_REQUEST_SIGNAL_STRENGTH, + .handler = ril_request_signal_strength, + }, + { + .request = RIL_REQUEST_QUERY_NETWORK_SELECTION_MODE, + .handler = ril_request_query_network_selection_mode, + }, + { + .request = RIL_REQUEST_SET_NETWORK_SELECTION_AUTOMATIC, + .handler = ril_request_set_network_selection_automatic, + }, + { + .request = RIL_REQUEST_SET_NETWORK_SELECTION_MANUAL, + .handler = ril_request_set_network_selection_manual, + }, + { + .request = RIL_REQUEST_OPERATOR, + .handler = ril_request_operator, + }, + { + .request = RIL_REQUEST_QUERY_AVAILABLE_NETWORKS, + .handler = ril_request_query_available_networks, + }, + { +#if RIL_VERSION >= 6 + .request = RIL_REQUEST_VOICE_REGISTRATION_STATE, + .handler = ril_request_voice_registration_state, +#else + .request = RIL_REQUEST_REGISTRATION_STATE, + .handler = ril_request_registration_state, +#endif + }, + { +#if RIL_VERSION >= 6 + .request = RIL_REQUEST_DATA_REGISTRATION_STATE, + .handler = ril_request_data_registration_state, +#else + .request = RIL_REQUEST_GPRS_REGISTRATION_STATE, + .handler = ril_request_gprs_registration_state, +#endif + }, + { + .request = RIL_REQUEST_GET_PREFERRED_NETWORK_TYPE, + .handler = ril_request_get_preferred_network_type, + }, + { + .request = RIL_REQUEST_SET_PREFERRED_NETWORK_TYPE, + .handler = ril_request_set_preferred_network_type, + }, + /* Sound */ + { + .request = RIL_REQUEST_SET_MUTE, + .handler = ril_request_set_mute, + }, + /* Misc */ + { + .request = RIL_REQUEST_BASEBAND_VERSION, + .handler = ril_request_baseband_version, + }, + { + .request = RIL_REQUEST_GET_IMSI, + .handler = ril_request_get_imsi, + }, + { + .request = RIL_REQUEST_GET_IMEI, + .handler = ril_request_get_imei, + }, + { + .request = RIL_REQUEST_GET_IMEISV, + .handler = ril_request_get_imeisv, + }, + { + .request = RIL_REQUEST_SCREEN_STATE, + .handler = ril_request_screen_state, + }, + /* OEM */ + { + .request = RIL_REQUEST_OEM_HOOK_RAW, + .handler = ril_request_oem_hook_raw, + }, + /* Data */ + { + .request = RIL_REQUEST_SETUP_DATA_CALL, + .handler = ril_request_setup_data_call, + }, + { + .request = RIL_REQUEST_DEACTIVATE_DATA_CALL, + .handler = ril_request_deactivate_data_call, + }, + { + .request = RIL_REQUEST_LAST_DATA_CALL_FAIL_CAUSE, + .handler = ril_request_last_data_call_fail_cause, + }, + { + .request = RIL_REQUEST_DATA_CALL_LIST, + .handler = ril_request_data_call_list, + }, +}; -int ril_request_id_set(int id) +unsigned int ril_request_handlers_count = sizeof(ril_request_handlers) / + sizeof(struct ril_request_handler); + +int ril_request_stats_log(void) { - id %= 0xff; + struct ril_request *request; + struct list_head *list; + unsigned int pending = 0; + unsigned int handled = 0; + unsigned int unhandled = 0; + unsigned int count = 0; + + if (ril_data == NULL) + return -1; + + RIL_REQUEST_LOCK(); + + list = ril_data->requests; + while (list != NULL) { + if (list->data == NULL) + goto list_continue; + + request = (struct ril_request *) list->data; + + switch (request->status) { + case RIL_REQUEST_PENDING: + pending++; + break; + case RIL_REQUEST_HANDLED: + handled++; + break; + case RIL_REQUEST_UNHANDLED: + unhandled++; + break; + } + + count++; + +list_continue: + list = list->next; + } + + RIL_LOGD("%d RIL request%s in the queue (%d pending, %d handled, %d unhandled)", count, count > 1 ? "s" : "", pending, handled, unhandled); + + count = 0; - while (ril_data.request_id < id) { - ril_data.request_id++; - ril_data.request_id %= 0xff; + list = ril_data->requests_data; + while (list != NULL) { + count++; + + list = list->next; } - return ril_data.request_id; + if (count > 0) + RIL_LOGD("%d RIL request%s data in the queue", count, count > 1 ? "s" : ""); + + RIL_REQUEST_UNLOCK(); + + return 0; } -int ril_request_register(RIL_Token t, int id) +int ril_request_register(int request, void *data, size_t size, RIL_Token token) { - struct ril_request_info *request; + struct ril_request *ril_request; struct list_head *list_end; struct list_head *list; + unsigned int i; - request = calloc(1, sizeof(struct ril_request_info)); - if (request == NULL) + if (ril_data == NULL) return -1; - request->token = t; - request->id = id; - request->canceled = 0; + RIL_REQUEST_LOCK(); + + ril_request = (struct ril_request *) calloc(1, sizeof(struct ril_request)); + ril_request->request = request; + ril_request->data = NULL; + ril_request->size = size; + ril_request->token = token; + ril_request->status = RIL_REQUEST_PENDING; - list_end = ril_data.requests; + if (size > 0) { + ril_request->data = calloc(1, size); + memcpy(ril_request->data, data, size); + } + + list_end = ril_data->requests; while (list_end != NULL && list_end->next != NULL) list_end = list_end->next; - list = list_head_alloc((void *) request, list_end, NULL); + list = list_head_alloc(list_end, NULL, (void *) ril_request); + + if (ril_data->requests == NULL) + ril_data->requests = list; + + for (i = 0; i < ril_clients_count; i++) { + if (ril_clients[i] == NULL) + continue; - if (ril_data.requests == NULL) - ril_data.requests = list; + ril_client_request_register(ril_clients[i], request, token); + } + + RIL_REQUEST_UNLOCK(); return 0; } -void ril_request_unregister(struct ril_request_info *request) +int ril_request_unregister(struct ril_request *request) { struct list_head *list; + unsigned int i; - if (request == NULL) - return; + if (request == NULL || ril_data == NULL) + return -1; + + RIL_REQUEST_LOCK(); + + for (i = 0; i < ril_clients_count; i++) { + if (ril_clients[i] == NULL) + continue; + + ril_client_request_unregister(ril_clients[i], request->request, request->token); + } - list = ril_data.requests; + list = ril_data->requests; while (list != NULL) { if (list->data == (void *) request) { - memset(request, 0, sizeof(struct ril_request_info)); + if (request->data != NULL && request->size > 0) + free(request->data); + + memset(request, 0, sizeof(struct ril_request)); free(request); - if (list == ril_data.requests) - ril_data.requests = list->next; + if (list == ril_data->requests) + ril_data->requests = list->next; list_head_free(list); break; } + list_continue: list = list->next; } + + RIL_REQUEST_UNLOCK(); + + return 0; } -struct ril_request_info *ril_request_info_find_id(int id) +int ril_request_flush(void) { - struct ril_request_info *request; + struct ril_request *request; struct list_head *list; + struct list_head *list_next; + + if (ril_data == NULL) + return -1; + + RIL_REQUEST_LOCK(); - list = ril_data.requests; + list = ril_data->requests; while (list != NULL) { - request = (struct ril_request_info *) list->data; - if (request == NULL) + if (list->data != NULL) { + request = (struct ril_request *) list->data; + + if (request->data != NULL && request->size > 0) + free(request->data); + + memset(request, 0, sizeof(struct ril_request)); + free(request); + } + + if (list == ril_data->requests) + ril_data->requests = list->next; + + list_next = list->next; + + list_head_free(list); + +list_continue: + list = list_next; + } + + RIL_REQUEST_UNLOCK(); + + return 0; +} + +struct ril_request *ril_request_find(void) +{ + struct ril_request *request; + struct list_head *list; + + if (ril_data == NULL) + return NULL; + + RIL_REQUEST_LOCK(); + + list = ril_data->requests; + while (list != NULL) { + if (list->data == NULL) goto list_continue; - if (request->id == id) - return request; + request = (struct ril_request *) list->data; + + RIL_REQUEST_UNLOCK(); + return request; list_continue: list = list->next; } + RIL_REQUEST_UNLOCK(); + return NULL; } -struct ril_request_info *ril_request_info_find_token(RIL_Token t) +struct ril_request *ril_request_find_request_status(int request, int status) { - struct ril_request_info *request; + struct ril_request *ril_request; struct list_head *list; - list = ril_data.requests; + if (ril_data == NULL) + return NULL; + + RIL_REQUEST_LOCK(); + + list = ril_data->requests; while (list != NULL) { - request = (struct ril_request_info *) list->data; - if (request == NULL) + if (list->data == NULL) goto list_continue; - if (request->token == t) - return request; + ril_request = (struct ril_request *) list->data; + + if (ril_request->request == request && ril_request->status == status) { + RIL_REQUEST_UNLOCK(); + return ril_request; + } list_continue: list = list->next; } + RIL_REQUEST_UNLOCK(); + return NULL; } -int ril_request_set_canceled(RIL_Token t, int canceled) +struct ril_request *ril_request_find_request(int request) { - struct ril_request_info *request; + struct ril_request *ril_request; + struct list_head *list; - request = ril_request_info_find_token(t); - if (request == NULL) - return -1; + if (ril_data == NULL) + return NULL; - request->canceled = canceled ? 1 : 0; + RIL_REQUEST_LOCK(); - return 0; -} + list = ril_data->requests; + while (list != NULL) { + if (list->data == NULL) + goto list_continue; -int ril_request_get_canceled(RIL_Token t) -{ - struct ril_request_info *request; + ril_request = (struct ril_request *) list->data; - request = ril_request_info_find_token(t); - if (request == NULL) - return -1; + if (ril_request->request == request) { + RIL_REQUEST_UNLOCK(); + return ril_request; + } + +list_continue: + list = list->next; + } + + RIL_REQUEST_UNLOCK(); - return request->canceled; + return NULL; } -RIL_Token ril_request_get_token(int id) +struct ril_request *ril_request_find_token(RIL_Token token) { - struct ril_request_info *request; + struct ril_request *request; + struct list_head *list; - request = ril_request_info_find_id(id); - if (request == NULL) - return RIL_TOKEN_NULL; + if (ril_data == NULL) + return NULL; + + RIL_REQUEST_LOCK(); + + list = ril_data->requests; + while (list != NULL) { + if (list->data == NULL) + goto list_continue; + + request = (struct ril_request *) list->data; + + if (request->token == token) { + RIL_REQUEST_UNLOCK(); + return request; + } + +list_continue: + list = list->next; + } - return request->token; + RIL_REQUEST_UNLOCK(); + + return NULL; } -int ril_request_get_id(RIL_Token t) +struct ril_request *ril_request_find_status(int status) { - struct ril_request_info *request; - int id, rc; + struct ril_request *request; + struct list_head *list; - request = ril_request_info_find_token(t); - if (request != NULL) - return request->id; + if (ril_data == NULL) + return NULL; - id = ril_request_id_get(); + RIL_REQUEST_LOCK(); - // Unregister a previous request with the same id - request = ril_request_info_find_id(id); - if (request != NULL) - ril_request_unregister(request); + list = ril_data->requests; + while (list != NULL) { + if (list->data == NULL) + goto list_continue; - rc = ril_request_register(t, id); - if (rc < 0) - return -1; + request = (struct ril_request *) list->data; + + if (request->status == status) { + RIL_REQUEST_UNLOCK(); + return request; + } - return id; +list_continue: + list = list->next; + } + + RIL_REQUEST_UNLOCK(); + + return NULL; } -void ril_request_complete(RIL_Token t, RIL_Errno e, void *data, size_t length) +int ril_request_complete(RIL_Token token, RIL_Errno error, void *data, + size_t size) { - struct ril_request_info *request; - int canceled = 0; + struct ril_request *request; + + if (ril_data == NULL || ril_data->env == NULL || ril_data->env->OnRequestComplete == NULL) + return -1; - request = ril_request_info_find_token(t); + if (token == NULL) + return 0; + + request = ril_request_find_token(token); if (request == NULL) goto complete; - canceled = ril_request_get_canceled(t); ril_request_unregister(request); - if (canceled) - return; + ril_request_stats_log(); complete: - ril_data.env->OnRequestComplete(t, e, data, length); + ril_data->env->OnRequestComplete(token, error, data, size); + + RIL_REQUEST_LOOP_UNLOCK(); + + return 0; } -void ril_request_unsolicited(int request, void *data, size_t length) +int ril_request_unsolicited(int request, void *data, size_t size) { - ril_data.env->OnUnsolicitedResponse(request, data, length); + if (ril_data == NULL || ril_data->env == NULL || ril_data->env->OnUnsolicitedResponse == NULL) + return -1; + + ril_data->env->OnUnsolicitedResponse(request, data, size); + + return 0; } -void ril_request_timed_callback(RIL_TimedCallback callback, void *data, const struct timeval *time) +int ril_request_timed_callback(RIL_TimedCallback callback, void *data, + const struct timeval *time) { - ril_data.env->RequestTimedCallback(callback, data, time); -} + if (ril_data == NULL || ril_data->env == NULL || ril_data->env->RequestTimedCallback == NULL) + return -1; -/* - * RIL radio state - */ + ril_data->env->RequestTimedCallback(callback, data, time); -int ril_radio_state_complete(RIL_RadioState radio_state, RIL_Token token) -{ - RIL_Errno error = RIL_E_SUCCESS; + return 0; +} - // This goes from best case of failure to worst case of failure - switch (radio_state) { - case RADIO_STATE_SIM_NOT_READY: - if (ril_data.state.radio_state == RADIO_STATE_SIM_NOT_READY) - error = RIL_E_GENERIC_FAILURE; - case RADIO_STATE_SIM_LOCKED_OR_ABSENT: - if (ril_data.state.radio_state == RADIO_STATE_SIM_LOCKED_OR_ABSENT) - error = RIL_E_GENERIC_FAILURE; - case RADIO_STATE_OFF: - if (ril_data.state.radio_state == RADIO_STATE_OFF) - error = RIL_E_RADIO_NOT_AVAILABLE; - case RADIO_STATE_UNAVAILABLE: - default: - if (ril_data.state.radio_state == RADIO_STATE_UNAVAILABLE) - error = RIL_E_RADIO_NOT_AVAILABLE; - break; - } +int ril_request_dispatch(struct ril_request *request) +{ + unsigned int i; + int status; + int rc; - if (error != RIL_E_SUCCESS) { - if (token != RIL_TOKEN_NULL) - ril_request_complete(token, error, NULL, 0); + if (request == NULL || ril_data == NULL) + return -1; - return 1; + for (i = 0; i < ril_request_handlers_count; i++) { + if (ril_request_handlers[i].handler == NULL) + continue; + + if (ril_request_handlers[i].request == request->request) { + status = ril_request_handlers[i].handler(request->data, request->size, request->token); + switch (status) { + case RIL_REQUEST_PENDING: + case RIL_REQUEST_HANDLED: + case RIL_REQUEST_UNHANDLED: + request->status = status; + break; + case RIL_REQUEST_COMPLETED: + break; + default: + RIL_LOGE("Handling RIL request %d failed", request->request); + return -1; + } + + return 0; + } } + RIL_LOGD("Unhandled RIL request: %d", request->request); + ril_request_complete(request->token, RIL_E_REQUEST_NOT_SUPPORTED, NULL, 0); + return 0; } -void ril_radio_state_update(RIL_RadioState radio_state) +void *ril_request_loop(void *data) { - RIL_LOGD("Setting radio state to %d", radio_state); - ril_data.state.radio_state = radio_state; + struct ril_request *request; + int rc; - ril_request_unsolicited(RIL_UNSOL_RESPONSE_RADIO_STATE_CHANGED, NULL, 0); + if (ril_data == NULL) + return NULL; + + while (1) { + RIL_REQUEST_LOOP_LOCK(); + + RIL_LOCK(); + + rc = ril_radio_state_check(RADIO_STATE_OFF); + if (rc < 0) { + RIL_UNLOCK(); + continue; + } - ril_tokens_check(); + do { + request = ril_request_find_status(RIL_REQUEST_UNHANDLED); + if (request == NULL) + break; + + request->status = RIL_REQUEST_PENDING; + } while (request != NULL); + + do { + request = ril_request_find_status(RIL_REQUEST_PENDING); + if (request == NULL) + break; + + rc = ril_request_dispatch(request); + if (rc < 0) + ril_request_unregister(request); + } while (request != NULL); + + RIL_UNLOCK(); + } + + return NULL; } /* - * RIL tokens + * RIL request data */ -void ril_tokens_check(void) +int ril_request_data_register(int request, void *data, size_t size) { - RIL_Token t; + struct ril_request_data *request_data; + struct list_head *list_end; + struct list_head *list; + unsigned int i; + + if (data == NULL || ril_data == NULL) + return -1; + + request_data = (struct ril_request_data *) calloc(1, sizeof(struct ril_request_data)); + request_data->request = request; + request_data->data = data; + request_data->size = size; + + list_end = ril_data->requests_data; + while (list_end != NULL && list_end->next != NULL) + list_end = list_end->next; + + list = list_head_alloc(list_end, NULL, (void *) request_data); + + if (ril_data->requests_data == NULL) + ril_data->requests_data = list; - if (ril_data.tokens.baseband_version != 0) { - if (ril_data.state.radio_state != RADIO_STATE_OFF) { - t = ril_data.tokens.baseband_version; - ril_data.tokens.baseband_version = 0; - ril_request_baseband_version(t); + return 0; +} + +int ril_request_data_unregister(struct ril_request_data *request_data) +{ + struct list_head *list; + unsigned int i; + + if (request_data == NULL || ril_data == NULL) + return -1; + + list = ril_data->requests_data; + while (list != NULL) { + if (list->data == (void *) request_data) { + memset(request_data, 0, sizeof(struct ril_request_data)); + free(request_data); + + if (list == ril_data->requests_data) + ril_data->requests_data = list->next; + + list_head_free(list); + + break; } + +list_continue: + list = list->next; } - if (ril_data.tokens.get_imei != 0 && ril_data.tokens.get_imeisv != 0) { - if (ril_data.state.radio_state != RADIO_STATE_OFF) { - t = ril_data.tokens.get_imei; - ril_data.tokens.get_imei = 0; - ril_request_get_imei(t); + return 0; +} + +int ril_request_data_flush(void) +{ + struct ril_request_data *request_data; + struct list_head *list; + struct list_head *list_next; + + if (ril_data == NULL) + return -1; + + list = ril_data->requests_data; + while (list != NULL) { + if (list->data != NULL) { + request_data = (struct ril_request_data *) list->data; + + if (request_data->data != NULL && request_data->size > 0) + free(request_data->data); + + memset(request_data, 0, sizeof(struct ril_request_data)); + free(request_data); } + + if (list == ril_data->requests_data) + ril_data->requests_data = list->next; + + list_next = list->next; + + list_head_free(list); + +list_continue: + list = list_next; } + + return 0; +} + +struct ril_request_data *ril_request_data_find_request(int request) +{ + struct ril_request_data *request_data; + struct list_head *list; + + if (ril_data == NULL) + return NULL; + + list = ril_data->requests_data; + while (list != NULL) { + if (list->data == NULL) + goto list_continue; + + request_data = (struct ril_request_data *) list->data; + + if (request_data->request == request) + return request_data; + +list_continue: + list = list->next; + } + + return NULL; +} + +int ril_request_data_free(int request) +{ + struct ril_request_data *request_data; + + do { + request_data = ril_request_data_find_request(request); + if (request_data == NULL) + break; + + if (request_data->data != NULL && request_data->size > 0) + free(request_data->data); + + ril_request_data_unregister(request_data); + } while (request_data != NULL); + + return 0; +} + +int ril_request_data_set(int request, void *data, size_t size) +{ + void *buffer; + int rc; + + if (data == NULL || size == 0) + return -1; + + buffer = calloc(1, size); + memcpy(buffer, data, size); + + rc = ril_request_data_register(request, buffer, size); + if (rc < 0) + return -1; + + return 0; +} + +int ril_request_data_set_uniq(int request, void *data, size_t size) +{ + int rc; + + ril_request_data_free(request); + + rc = ril_request_data_set(request, data, size); + if (rc < 0) + return -1; + + return 0; +} + +size_t ril_request_data_size_get(int request) +{ + struct ril_request_data *request_data; + + request_data = ril_request_data_find_request(request); + if (request_data == NULL) + return 0; + + return request_data->size; +} + +void *ril_request_data_get(int request) +{ + struct ril_request_data *request_data; + void *buffer; + + request_data = ril_request_data_find_request(request); + if (request_data == NULL) + return NULL; + + buffer = request_data->data; + + ril_request_data_unregister(request_data); + + return buffer; } /* - * Clients dispatch functions + * RIL radio state */ -void ipc_fmt_dispatch(struct ipc_message_info *info) +int ril_radio_state_update(RIL_RadioState radio_state) { - if (info == NULL) - return; + struct ril_request *request; + unsigned int i; + int rc; - RIL_LOCK(); + if (ril_data == NULL) + return -1; - ril_request_id_set(info->aseq); + if (ril_data->radio_state == radio_state) + return 0; - switch (IPC_COMMAND(info)) { - /* GEN */ - case IPC_GEN_PHONE_RES: - ipc_gen_phone_res(info); - break; - /* PWR */ - case IPC_PWR_PHONE_PWR_UP: - ipc_pwr_phone_pwr_up(); - break; - case IPC_PWR_PHONE_RESET: - ipc_pwr_phone_reset(); - break; - case IPC_PWR_PHONE_STATE: - ipc_pwr_phone_state(info); - break; - /* DISP */ - case IPC_DISP_ICON_INFO: - ipc_disp_icon_info(info); - break; - case IPC_DISP_RSSI_INFO: - ipc_disp_rssi_info(info); - break; - /* MISC */ - case IPC_MISC_ME_SN: - ipc_misc_me_sn(info); - break; - case IPC_MISC_ME_VERSION: - ipc_misc_me_version(info); - break; - case IPC_MISC_ME_IMSI: - ipc_misc_me_imsi(info); - break; - case IPC_MISC_TIME_INFO: - ipc_misc_time_info(info); - break; - /* SAT */ -#ifndef DISABLE_STK - case IPC_SAT_PROACTIVE_CMD: - ipc_sat_proactive_cmd(info); - break; - case IPC_SAT_ENVELOPE_CMD: - ipc_sat_envelope_cmd(info); - break; -#endif - /* SS */ - case IPC_SS_USSD: - ipc_ss_ussd(info); - break; - /* SEC */ - case IPC_SEC_SIM_STATUS: - ipc_sec_sim_status(info); - break; - case IPC_SEC_SIM_ICC_TYPE: - ipc_sec_sim_icc_type(info); - break; - case IPC_SEC_LOCK_INFO: - ipc_sec_lock_info(info); - break; - case IPC_SEC_RSIM_ACCESS: - ipc_sec_rsim_access(info); - break; - case IPC_SEC_PHONE_LOCK: - ipc_sec_phone_lock(info); - break; - /* NET */ - case IPC_NET_CURRENT_PLMN: - ipc_net_current_plmn(info); - break; - case IPC_NET_REGIST: - ipc_net_regist(info); - break; - case IPC_NET_PLMN_LIST: - ipc_net_plmn_list(info); - break; - case IPC_NET_PLMN_SEL: - ipc_net_plmn_sel(info); - break; - case IPC_NET_MODE_SEL: - ipc_net_mode_sel(info); - break; - /* SMS */ - case IPC_SMS_INCOMING_MSG: - ipc_sms_incoming_msg(info); - break; - case IPC_SMS_DELIVER_REPORT: - ipc_sms_deliver_report(info); - break; - case IPC_SMS_SVC_CENTER_ADDR: - ipc_sms_svc_center_addr(info); - break; - case IPC_SMS_SEND_MSG: - ipc_sms_send_msg(info); - break; - case IPC_SMS_DEVICE_READY: - ipc_sms_device_ready(info); - break; - case IPC_SMS_SAVE_MSG: - ipc_sms_save_msg(info); - break; - case IPC_SMS_DEL_MSG: - ipc_sms_del_msg(info); - break; - /* SVC */ - case IPC_SVC_DISPLAY_SCREEN: - ipc_svc_display_screen(info); - break; - /* CALL */ - case IPC_CALL_INCOMING: - ipc_call_incoming(info); - break; - case IPC_CALL_LIST: - ipc_call_list(info); - break; - case IPC_CALL_STATUS: - ipc_call_status(info); - break; - case IPC_CALL_BURST_DTMF: - ipc_call_burst_dtmf(info); - break; - /* GPRS */ - case IPC_GPRS_IP_CONFIGURATION: - ipc_gprs_ip_configuration(info); - break; - case IPC_GPRS_CALL_STATUS: - ipc_gprs_call_status(info); - break; - case IPC_GPRS_PDP_CONTEXT: - ipc_gprs_pdp_context(info); + RIL_LOGD("Updating RIL radio state to %d", radio_state); + + ril_data->radio_state = radio_state; + ril_request_unsolicited(RIL_UNSOL_RESPONSE_RADIO_STATE_CHANGED, NULL, 0); + + switch (ril_data->radio_state) { + case RADIO_STATE_UNAVAILABLE: + do { + request = ril_request_find(); + if (request == NULL) + break; + + ril_request_complete(request->token, RIL_E_RADIO_NOT_AVAILABLE, NULL, 0); + + ril_request_unregister(request); + } while (request != NULL); + + ril_request_flush(); + ril_request_data_flush(); + + ril_request_stats_log(); + + for (i = 0; i < ril_clients_count; i++) { + if (ril_clients[i] == NULL) + continue; + + ril_client_flush(ril_clients[i]); + } + case RADIO_STATE_OFF: + ril_data_connection_flush(); + + ril_request_unsolicited(RIL_UNSOL_RESPONSE_CALL_STATE_CHANGED, NULL, 0); + ril_request_unsolicited(RIL_UNSOL_RESPONSE_VOICE_NETWORK_STATE_CHANGED, NULL, 0); + ril_request_unsolicited(RIL_UNSOL_DATA_CALL_LIST_CHANGED, NULL, 0); + ril_request_unsolicited(RIL_UNSOL_RESPONSE_SIM_STATUS_CHANGED, NULL, 0); break; default: - RIL_LOGE("%s: Unhandled request: %s (%04x)", __func__, ipc_command_to_str(IPC_COMMAND(info)), IPC_COMMAND(info)); + RIL_REQUEST_LOOP_UNLOCK(); break; } - RIL_UNLOCK(); + return 0; } -void ipc_rfs_dispatch(struct ipc_message_info *info) +int ril_radio_state_check(RIL_RadioState radio_state) { - if (info == NULL) - return; + RIL_RadioState radio_states[] = { + RADIO_STATE_UNAVAILABLE, + RADIO_STATE_OFF, + RADIO_STATE_ON, + RADIO_STATE_NV_NOT_READY, + RADIO_STATE_NV_READY, + RADIO_STATE_SIM_NOT_READY, + RADIO_STATE_SIM_LOCKED_OR_ABSENT, + RADIO_STATE_SIM_READY, + }; + unsigned int index; + unsigned int count; + unsigned int i; + + if (ril_data == NULL) + return -1; - RIL_LOCK(); + count = sizeof(radio_states) / sizeof(RIL_RadioState); - switch (IPC_COMMAND(info)) { - case IPC_RFS_NV_READ_ITEM: - ipc_rfs_nv_read_item(info); - break; - case IPC_RFS_NV_WRITE_ITEM: - ipc_rfs_nv_write_item(info); + for (i = 0; i < count; i++) + if (radio_states[i] == radio_state) break; - default: - RIL_LOGE("%s: Unhandled request: %s (%04x)", __func__, ipc_command_to_str(IPC_COMMAND(info)), IPC_COMMAND(info)); + + index = i; + + for (i = 0; i < count; i++) + if (radio_states[i] == ril_data->radio_state) break; - } - RIL_UNLOCK(); + if (i < index) + return -1; + + return 0; } -void srs_dispatch(struct srs_message *message) +/* + * RIL data + */ + +int ril_data_create(void) { - if (message == NULL) - return; + ril_data = (struct ril_data *) calloc(1, sizeof(struct ril_data)); - RIL_LOCK(); + pthread_mutex_init(&ril_data->mutex, NULL); + pthread_mutex_init(&ril_data->request_mutex, NULL); + pthread_mutex_init(&ril_data->request_loop_mutex, NULL); - switch (message->command) { - case SRS_CONTROL_PING: - srs_control_ping(message); - break; - case SRS_SND_SET_CALL_CLOCK_SYNC: - srs_snd_set_call_clock_sync(message); - break; - case SRS_SND_SET_CALL_VOLUME: - srs_snd_set_call_volume(message); - break; - case SRS_SND_SET_CALL_AUDIO_PATH: - srs_snd_set_call_audio_path(message); - break; - default: - RIL_LOGE("%s: Unhandled request: (%04x)", __func__, message->command); - break; - } + RIL_REQUEST_LOOP_LOCK(); - RIL_UNLOCK(); + ril_data->radio_state = RADIO_STATE_UNAVAILABLE; + + return 0; +} + +int ril_data_destroy(void) +{ + if (ril_data == NULL) + return -1; + + pthread_mutex_destroy(&ril_data->mutex); + pthread_mutex_destroy(&ril_data->request_mutex); + pthread_mutex_destroy(&ril_data->request_loop_mutex); + + free(ril_data); + ril_data = NULL; + + return 0; } /* * RIL interface */ -void ril_on_request(int request, void *data, size_t length, RIL_Token t) +void ril_on_request(int request, void *data, size_t size, RIL_Token token) { + struct ril_request *ril_request; + void *buffer = NULL; + unsigned int strings_count = 0; + unsigned int i; + char *c; + RIL_LOCK(); + ril_request = ril_request_find_token(token); + if (ril_request != NULL) + ril_request_unregister(ril_request); + switch (request) { - /* PWR */ - case RIL_REQUEST_RADIO_POWER: - ril_request_radio_power(t, data, length); - break; - case RIL_REQUEST_BASEBAND_VERSION: - ril_request_baseband_version(t); - break; - /* DISP */ - case RIL_REQUEST_SIGNAL_STRENGTH: - ril_request_signal_strength(t); - break; - /* MISC */ - case RIL_REQUEST_GET_IMEI: - ril_request_get_imei(t); - break; - case RIL_REQUEST_GET_IMEISV: - ril_request_get_imeisv(t); - break; - case RIL_REQUEST_GET_IMSI: - ril_request_get_imsi(t); - break; - /* SAT */ -#ifndef DISABLE_STK - case RIL_REQUEST_REPORT_STK_SERVICE_IS_RUNNING: - ril_request_report_stk_service_is_running(t); - break; - case RIL_REQUEST_STK_SEND_TERMINAL_RESPONSE: - ril_request_stk_send_terminal_response(t, data, length); - break; - case RIL_REQUEST_STK_SEND_ENVELOPE_COMMAND: - ril_request_stk_send_envelope_command(t, data, length); - break; - case RIL_REQUEST_STK_HANDLE_CALL_SETUP_REQUESTED_FROM_SIM: - ril_request_complete(t, RIL_E_SUCCESS, NULL, 0); - break; -#endif - /* SS */ - case RIL_REQUEST_SEND_USSD: - ril_request_send_ussd(t, data, length); - break; - case RIL_REQUEST_CANCEL_USSD: - ril_request_cancel_ussd(t, data, length); - break; - /* SEC */ - case RIL_REQUEST_GET_SIM_STATUS: - ril_request_get_sim_status(t); - break; - case RIL_REQUEST_SIM_IO: - ril_request_sim_io(t, data, length); - break; - case RIL_REQUEST_ENTER_SIM_PIN: - ril_request_enter_sim_pin(t, data, length); - break; - case RIL_REQUEST_CHANGE_SIM_PIN: - ril_request_change_sim_pin(t, data, length); + case RIL_REQUEST_DIAL: + if (data == NULL || size < sizeof(RIL_Dial)) + break; + + buffer = calloc(1, size); + + memcpy(buffer, data, size); + + if (((RIL_Dial *) data)->address != NULL) + ((RIL_Dial *) buffer)->address = strdup(((RIL_Dial *) data)->address); + + data = buffer; break; - case RIL_REQUEST_ENTER_SIM_PUK: - ril_request_enter_sim_puk(t, data, length); + case RIL_REQUEST_WRITE_SMS_TO_SIM: + if (data == NULL || size < sizeof(RIL_SMS_WriteArgs)) + break; + + + buffer = calloc(1, size); + + memcpy(buffer, data, size); + + if (((RIL_SMS_WriteArgs *) data)->pdu != NULL) + ((RIL_SMS_WriteArgs *) buffer)->pdu = strdup(((RIL_SMS_WriteArgs *) data)->pdu); + + if (((RIL_SMS_WriteArgs *) data)->smsc != NULL) + ((RIL_SMS_WriteArgs *) buffer)->smsc = strdup(((RIL_SMS_WriteArgs *) data)->smsc); + + data = buffer; break; + case RIL_REQUEST_SEND_SMS: + case RIL_REQUEST_SEND_SMS_EXPECT_MORE: case RIL_REQUEST_QUERY_FACILITY_LOCK: - ril_request_query_facility_lock(t, data, length); - break; case RIL_REQUEST_SET_FACILITY_LOCK: - ril_request_set_facility_lock(t, data, length); - break; - /* SVC */ - case RIL_REQUEST_OEM_HOOK_RAW: - ril_request_oem_hook_raw(t, data, length); - break; - /* NET */ - case RIL_REQUEST_OPERATOR: - ril_request_operator(t); + case RIL_REQUEST_ENTER_SIM_PIN: + case RIL_REQUEST_ENTER_SIM_PUK: + case RIL_REQUEST_ENTER_SIM_PIN2: + case RIL_REQUEST_ENTER_SIM_PUK2: + case RIL_REQUEST_CHANGE_SIM_PIN: + case RIL_REQUEST_CHANGE_SIM_PIN2: + strings_count = size / sizeof(char *); break; + case RIL_REQUEST_SIM_IO: #if RIL_VERSION >= 6 - case RIL_REQUEST_VOICE_REGISTRATION_STATE: - ril_request_voice_registration_state(t); - break; - case RIL_REQUEST_DATA_REGISTRATION_STATE: - ril_request_data_registration_state(t); - break; + if (data == NULL || size < sizeof(RIL_SIM_IO_v6)) #else - case RIL_REQUEST_REGISTRATION_STATE: - ril_request_registration_state(t); - break; - case RIL_REQUEST_GPRS_REGISTRATION_STATE: - ril_request_gprs_registration_state(t); - break; + if (data == NULL || size < sizeof(RIL_SIM_IO)) #endif - case RIL_REQUEST_QUERY_AVAILABLE_NETWORKS: - ril_request_query_available_networks(t); - break; - case RIL_REQUEST_GET_PREFERRED_NETWORK_TYPE: - ril_request_get_preferred_network_type(t); - break; - case RIL_REQUEST_SET_PREFERRED_NETWORK_TYPE: - ril_request_set_preferred_network_type(t, data, length); - break; - case RIL_REQUEST_QUERY_NETWORK_SELECTION_MODE: - ril_request_query_network_selection_mode(t); - break; - case RIL_REQUEST_SET_NETWORK_SELECTION_AUTOMATIC: - ril_request_set_network_selection_automatic(t); - break; - case RIL_REQUEST_SET_NETWORK_SELECTION_MANUAL: - ril_request_set_network_selection_manual(t, data, length); - break; - /* SMS */ - case RIL_REQUEST_SEND_SMS: - ril_request_send_sms(t, data, length); - break; - case RIL_REQUEST_SEND_SMS_EXPECT_MORE: - ril_request_send_sms_expect_more(t, data, length); - break; - case RIL_REQUEST_SMS_ACKNOWLEDGE: - ril_request_sms_acknowledge(t, data, length); - break; - case RIL_REQUEST_WRITE_SMS_TO_SIM: - ril_request_write_sms_to_sim(t, data, length); - break; - case RIL_REQUEST_DELETE_SMS_ON_SIM: - ril_request_delete_sms_on_sim(t, data, length); - break; - /* CALL */ - case RIL_REQUEST_DIAL: - ril_request_dial(t, data, length); - break; - case RIL_REQUEST_GET_CURRENT_CALLS: - ril_request_get_current_calls(t); - break; - case RIL_REQUEST_HANGUP: - case RIL_REQUEST_HANGUP_WAITING_OR_BACKGROUND: - case RIL_REQUEST_HANGUP_FOREGROUND_RESUME_BACKGROUND: - ril_request_hangup(t); - break; - case RIL_REQUEST_ANSWER: - ril_request_answer(t); - break; - case RIL_REQUEST_LAST_CALL_FAIL_CAUSE: - ril_request_last_call_fail_cause(t); - break; - case RIL_REQUEST_DTMF: - ril_request_dtmf(t, data, length); - break; - case RIL_REQUEST_DTMF_START: - ril_request_dtmf_start(t, data, length); - break; - case RIL_REQUEST_DTMF_STOP: - ril_request_dtmf_stop(t); + break; + + buffer = calloc(1, size); + + memcpy(buffer, data, size); + +#if RIL_VERSION >= 6 + if (((RIL_SIM_IO_v6 *) data)->path != NULL) + ((RIL_SIM_IO_v6 *) buffer)->path = strdup(((RIL_SIM_IO_v6 *) data)->path); + + if (((RIL_SIM_IO_v6 *) data)->data != NULL) + ((RIL_SIM_IO_v6 *) buffer)->data = strdup(((RIL_SIM_IO_v6 *) data)->data); + + if (((RIL_SIM_IO_v6 *) data)->pin2 != NULL) + ((RIL_SIM_IO_v6 *) buffer)->pin2 = strdup(((RIL_SIM_IO_v6 *) data)->pin2); + + if (((RIL_SIM_IO_v6 *) data)->aidPtr != NULL) + ((RIL_SIM_IO_v6 *) buffer)->aidPtr = strdup(((RIL_SIM_IO_v6 *) data)->aidPtr); +#else + if (((RIL_SIM_IO *) data)->path != NULL) + ((RIL_SIM_IO *) buffer)->path = strdup(((RIL_SIM_IO *) data)->path); + + if (((RIL_SIM_IO *) data)->data != NULL) + ((RIL_SIM_IO *) buffer)->data = strdup(((RIL_SIM_IO *) data)->data); + + if (((RIL_SIM_IO *) data)->pin2 != NULL) + ((RIL_SIM_IO *) buffer)->pin2 = strdup(((RIL_SIM_IO *) data)->pin2); +#endif + + data = buffer; break; - /* GPRS */ case RIL_REQUEST_SETUP_DATA_CALL: - ril_request_setup_data_call(t, data, length); - break; case RIL_REQUEST_DEACTIVATE_DATA_CALL: - ril_request_deactivate_data_call(t, data, length); - break; - case RIL_REQUEST_LAST_DATA_CALL_FAIL_CAUSE: - ril_request_last_data_call_fail_cause(t); - break; - case RIL_REQUEST_DATA_CALL_LIST: - ril_request_data_call_list(t); - break; - /* SND */ - case RIL_REQUEST_SET_MUTE: - ril_request_set_mute(t, data, length); - break; - /* OTHER */ - case RIL_REQUEST_SCREEN_STATE: - /* This doesn't affect anything */ - ril_request_complete(t, RIL_E_SUCCESS, NULL, 0); + strings_count = size / sizeof(char *); break; default: - RIL_LOGE("%s: Unhandled request: %d", __func__, request); - ril_request_complete(t, RIL_E_REQUEST_NOT_SUPPORTED, NULL, 0); + if (data == NULL || size != sizeof(char *)) + break; + + c = (char *) data; + + for (i = 0; isprint(c[i]); i++); + + if (i > 0 && c[i] == '\0') { + size = i + 1; + RIL_LOGD("Detected string with a size of %d byte%s", size, size > 0 ? "s" : ""); + } + break; } + if (strings_count > 0 && data != NULL && size >= strings_count * sizeof(char *)) { + buffer = calloc(1, size); + + for (i = 0; i < strings_count; i++) { + if (((char **) data)[i] != NULL) { + c = strdup(((char **) data)[i]); + ((char **) buffer)[i] = c; + } + } + + data = buffer; + } + + ril_request_register(request, data, size, token); + + if (buffer != NULL) + free(buffer); + + ril_request_stats_log(); + RIL_UNLOCK(); + + RIL_REQUEST_LOOP_UNLOCK(); } + RIL_RadioState ril_on_state_request(void) { - return ril_data.state.radio_state; -} + if (ril_data == NULL) + return RADIO_STATE_UNAVAILABLE; -int ril_on_supports(int request) -{ - return 1; + return ril_data->radio_state; } -void ril_on_cancel(RIL_Token t) +int ril_supports(int request) { - ril_request_set_canceled(t, 1); + unsigned int i; + + for (i = 0; i < ril_request_handlers_count; i++) { + if (ril_request_handlers[i].handler == NULL) + continue; + + if (ril_request_handlers[i].request == request) + return 1; + } + + return 0; } -const char *ril_get_version(void) +void ril_on_cancel(RIL_Token token) { - return RIL_VERSION_STRING; -} + struct ril_request *request; -/* - * RIL init - */ + RIL_LOCK(); -void ril_data_init(void) -{ - memset(&ril_data, 0, sizeof(ril_data)); + request = ril_request_find_token(token); + if (request == NULL) { + RIL_UNLOCK(); + return; + } - pthread_mutex_init(&ril_data.mutex, NULL); + ril_request_unregister(request); - ril_data.state.radio_state = RADIO_STATE_UNAVAILABLE; + ril_request_stats_log(); + + RIL_UNLOCK(); } -/* - * RIL interface - */ +const char *ril_get_version(void) +{ + return RIL_VERSION_STRING; +} -static const RIL_RadioFunctions ril_ops = { - RIL_VERSION >= 6 ? 6 : RIL_VERSION, +RIL_RadioFunctions ril_radio_functions = { + RIL_VERSION, ril_on_request, ril_on_state_request, - ril_on_supports, + ril_supports, ril_on_cancel, ril_get_version }; -const RIL_RadioFunctions *RIL_Init(const struct RIL_Env *env, int argc, char **argv) +const RIL_RadioFunctions *RIL_Init(const struct RIL_Env *env, int argc, + char **argv) { - struct ril_client *ipc_fmt_client; - struct ril_client *ipc_rfs_client; - struct ril_client *srs_client; + RIL_RadioFunctions *radio_functions; + pthread_attr_t attr; + unsigned int i; int rc; if (env == NULL) return NULL; - ril_data_init(); - ril_data.env = (struct RIL_Env *) env; - - RIL_LOCK(); - - RIL_LOGD("Creating IPC FMT client"); - - ipc_fmt_client = ril_client_new(&ipc_fmt_client_funcs); - rc = ril_client_create(ipc_fmt_client); - + rc = ril_data_create(); if (rc < 0) { - RIL_LOGE("IPC FMT client creation failed."); - goto ipc_rfs; - } - - rc = ril_client_thread_start(ipc_fmt_client); - - if (rc < 0) { - RIL_LOGE("IPC FMT thread creation failed."); - goto ipc_rfs; + RIL_LOGE("Creating RIL data failed"); + return NULL; } - ril_data.ipc_fmt_client = ipc_fmt_client; - RIL_LOGD("IPC FMT client ready"); - -ipc_rfs: - RIL_LOGD("Creating IPC RFS client"); - - ipc_rfs_client = ril_client_new(&ipc_rfs_client_funcs); - rc = ril_client_create(ipc_rfs_client); + RIL_LOCK(); - if (rc < 0) { - RIL_LOGE("IPC RFS client creation failed."); - goto srs; - } + ril_data->env = env; - rc = ril_client_thread_start(ipc_rfs_client); + for (i = 0; i < ril_clients_count; i++) { + if (ril_clients[i] == NULL) + continue; - if (rc < 0) { - RIL_LOGE("IPC RFS thread creation failed."); - goto srs; + rc = ril_client_create(ril_clients[i]); + if (rc < 0) + goto error; } - ril_data.ipc_rfs_client = ipc_rfs_client; - RIL_LOGD("IPC RFS client ready"); - -srs: - RIL_LOGD("Creating SRS client"); + for (i = 0; i < ril_clients_count; i++) { + if (ril_clients[i] == NULL) + continue; - srs_client = ril_client_new(&srs_client_funcs); - rc = ril_client_create(srs_client); + rc = ril_client_open(ril_clients[i]); + if (rc < 0) + goto error; - if (rc < 0) { - RIL_LOGE("SRS client creation failed."); - goto end; + rc = ril_client_loop(ril_clients[i]); + if (rc < 0) + goto error; } - rc = ril_client_thread_start(srs_client); + pthread_attr_init(&attr); + pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED); - if (rc < 0) { - RIL_LOGE("SRS thread creation failed."); - goto end; + rc = pthread_create(&ril_data->request_thread, &attr, ril_request_loop, NULL); + if (rc != 0) { + RIL_LOGE("Starting request loop failed"); + goto error; } - ril_data.srs_client = srs_client; - RIL_LOGD("SRS client ready"); + radio_functions = &ril_radio_functions; + goto complete; -end: +error: + radio_functions = NULL; + +complete: RIL_UNLOCK(); - return &ril_ops; + return radio_functions; } |