| |
| /****************************************************************************** |
| *(C) Copyright 2015 Marvell International Ltd. |
| * All Rights Reserved |
| ******************************************************************************/ |
| |
| #include <errno.h> |
| #include <unistd.h> |
| #include <stdio.h> |
| #include <string.h> |
| #include <stdlib.h> |
| #include <libubox/blob.h> |
| #include <libubox/blobmsg.h> |
| #include <libubox/ustream.h> |
| #include <libubus.h> |
| #include <ubusmsg.h> |
| #include <include/log.h> |
| #include <cm.h> |
| #include "ril.h" |
| #include "rilutil.h" |
| #include "chl.h" |
| #include "chl_main.h" |
| #include "chl_ril.h" |
| #include "chl_ubus.h" |
| #include "chl_util.h" |
| |
| #define RIL_NAME "ril" |
| #define RIL_REQ "ril_request" |
| #define RIL_MAX_RETRIES 20 |
| #define SIM_MAX_RETRIES 10 |
| #define RIL_REQ_TIMEOUT 20000 |
| #define RIL_NUM_SETUP_DATA_CALL_PARAMS 7 |
| |
| struct chl_ril_context { |
| int ril_err; |
| int dcl_num; |
| Ubus_Data_Call_Response *dcr; |
| int pin_status; |
| int ps_attach_status; |
| }; |
| |
| static const char *ril_unsol_events[] = { |
| "ril.unsol.mm", |
| "ril.unsol.ps", |
| }; |
| |
| static bool ps_attached = false; |
| static bool ril_stub = false; |
| static unsigned int ril_id; |
| static struct blob_buf blob; |
| static struct ubus_subscriber ril_subscriber; |
| static struct chl_ril_context ril_ctx; |
| |
| |
| static struct chl_ril_context *chl_ril_context_get(void) |
| { |
| memset(&ril_ctx, 0, sizeof(struct chl_ril_context)); |
| return &ril_ctx; |
| } |
| |
| static void chl_ril_context_done(struct chl_ril_context *rctx) |
| { |
| if (rctx->dcr) |
| free(rctx->dcr); |
| } |
| |
| static char *ril_ip_type_to_str(enum ip_type type) |
| { |
| switch(type) { |
| case IPV4: |
| return IPV4_STR; |
| case IPV6: |
| return IPV6_STR; |
| case IPV4V6: |
| return IPV4V6_STR; |
| default: |
| return ""; |
| } |
| } |
| |
| char *data_call_fail_to_str(RIL_DataCallFailCause fail) |
| { |
| switch(fail) { |
| case PDP_FAIL_NONE: |
| return "PDP_FAIL_NONE"; |
| case PDP_FAIL_OPERATOR_BARRED: |
| return "PDP_FAIL_OPERATOR_BARRED"; |
| case PDP_FAIL_INSUFFICIENT_RESOURCES: |
| return "PDP_FAIL_INSUFFICIENT_RESOURCES"; |
| case PDP_FAIL_MISSING_UKNOWN_APN: |
| return "PDP_FAIL_MISSING_UKNOWN_APN"; |
| case PDP_FAIL_UNKNOWN_PDP_ADDRESS_TYPE: |
| return "PDP_FAIL_UNKNOWN_PDP_ADDRESS_TYPE"; |
| case PDP_FAIL_USER_AUTHENTICATION: |
| return "PDP_FAIL_USER_AUTHENTICATION"; |
| case PDP_FAIL_ACTIVATION_REJECT_GGSN: |
| return "PDP_FAIL_ACTIVATION_REJECT_GGSN"; |
| case PDP_FAIL_ACTIVATION_REJECT_UNSPECIFIED: |
| return "PDP_FAIL_ACTIVATION_REJECT_UNSPECIFIED"; |
| case PDP_FAIL_SERVICE_OPTION_NOT_SUPPORTED: |
| return "PDP_FAIL_SERVICE_OPTION_NOT_SUPPORTED"; |
| case PDP_FAIL_SERVICE_OPTION_NOT_SUBSCRIBED: |
| return "PDP_FAIL_SERVICE_OPTION_NOT_SUBSCRIBED"; |
| case PDP_FAIL_SERVICE_OPTION_OUT_OF_ORDER: |
| return "PDP_FAIL_SERVICE_OPTION_OUT_OF_ORDER"; |
| case PDP_FAIL_NSAPI_IN_USE: |
| return "PDP_FAIL_NSAPI_IN_USE"; |
| case PDP_FAIL_REGULAR_DEACTIVATION: |
| return "PDP_FAIL_REGULAR_DEACTIVATION"; |
| case PDP_FAIL_ONLY_IPV4_ALLOWED: |
| return "PDP_FAIL_ONLY_IPV4_ALLOWED"; |
| case PDP_FAIL_ONLY_IPV6_ALLOWED: |
| return "PDP_FAIL_ONLY_IPV6_ALLOWED"; |
| case PDP_FAIL_ONLY_SINGLE_BEARER_ALLOWED: |
| return "PDP_FAIL_ONLY_SINGLE_BEARER_ALLOWED"; |
| case PDP_FAIL_PROTOCOL_ERRORS: |
| return "PDP_FAIL_PROTOCOL_ERRORS"; |
| case PDP_FAIL_VOICE_REGISTRATION_FAIL: |
| return "PDP_FAIL_VOICE_REGISTRATION_FAIL"; |
| case PDP_FAIL_DATA_REGISTRATION_FAIL: |
| return "PDP_FAIL_DATA_REGISTRATION_FAIL"; |
| case PDP_FAIL_SIGNAL_LOST: |
| return "PDP_FAIL_SIGNAL_LOST"; |
| case PDP_FAIL_PREF_RADIO_TECH_CHANGED: |
| return "PDP_FAIL_PREF_RADIO_TECH_CHANGED"; |
| case PDP_FAIL_RADIO_POWER_OFF: |
| return "PDP_FAIL_RADIO_POWER_OFF"; |
| case PDP_FAIL_TETHERED_CALL_ACTIVE: |
| return "PDP_FAIL_TETHERED_CALL_ACTIVE"; |
| case PDP_FAIL_ERROR_UNSPECIFIED: |
| return "PDP_FAIL_ERROR_UNSPECIFIED"; |
| default: |
| return "Unknown"; |
| } |
| } |
| |
| static char *ril_req_to_str(int req_num) |
| { |
| switch(req_num) { |
| case RIL_REQUEST_GET_SIM_STATUS: |
| return "RIL_REQUEST_GET_SIM_STATUS"; |
| break; |
| case RIL_REQUEST_DATA_CALL_LIST: |
| return "RIL_REQUEST_DATA_CALL_LIST"; |
| break; |
| case RIL_REQUEST_SETUP_DATA_CALL: |
| return "RIL_REQUEST_SETUP_DATA_CALL"; |
| break; |
| case RIL_REQUEST_DEACTIVATE_DATA_CALL: |
| return "RIL_REQUEST_DEACTIVATE_DATA_CALL"; |
| break; |
| case RIL_REQUEST_SET_INITIAL_ATTACH_APN: |
| return "RIL_REQUEST_SET_INITIAL_ATTACH_APN"; |
| break; |
| default: |
| return "unknown"; |
| } |
| } |
| |
| int chl_ril_type_to_int(char *type) |
| { |
| if (!strcmp(type, IPV4_STR)) |
| return IPV4; |
| else if (!strcmp(type, IPV6_STR)) |
| return IPV6; |
| else if (!strcmp(type, IPV4V6_STR)) |
| return IPV4V6; |
| else |
| { |
| CHL_ERR("bad ip type in response, setting ipv4v6\n"); |
| return IPV4V6; |
| } |
| } |
| |
| static void chl_ril_setup_data_call_stub(struct chl_pdp *pdp, bool activate, |
| Ubus_Data_Call_Response *rsp) |
| { |
| static int cid_n = 1; |
| static int ip = 1; |
| static int ip6 = 1; |
| |
| if (!activate) |
| return; |
| |
| |
| CHL_INFO("generating PDP info\n"); |
| |
| rsp->status = PDP_FAIL_NONE; |
| rsp->cid = cid_n; |
| |
| switch (pdp->type) { |
| case IPV4: |
| strcpy(rsp->type, IPV4_STR); |
| sprintf(rsp->addresses, "%d.%d.%d.%d", ip, ip, ip, ip); |
| sprintf(rsp->dnses, "%d.%d.%d.100 %d.%d.%d.200", |
| ip, ip, ip, ip, ip, ip); |
| break; |
| case IPV6: |
| strcpy(rsp->type, IPV6_STR); |
| sprintf(rsp->addresses, "fe80:%d%d%d::1", ip6, ip6, ip6); |
| sprintf(rsp->dnses, "2002:%d%d%d::2 2002:%d%d%d::3", |
| ip, ip, ip, ip, ip, ip); |
| break; |
| case IPV4V6: |
| default: |
| strcpy(rsp->type, IPV4V6_STR); |
| sprintf(rsp->addresses, "%d.%d.%d.%d fe80:%d%d%d::3", |
| ip, ip, ip, ip, ip6, ip6, ip6); |
| sprintf(rsp->dnses, "%d.%d.%d.100 2002:%d%d%d::2", |
| ip, ip, ip, ip6, ip6, ip6); |
| break; |
| } |
| |
| cid_n++; |
| ip++; |
| ip6++; |
| } |
| |
| static void chl_ps_attach_status_change(int status) |
| { |
| if (!status) { |
| CHL_INFO("PS DETACHED\n"); |
| ps_attached = false; |
| } else if (status == 1) { |
| ps_attached = true; |
| chl_retry_open_all(); |
| } |
| } |
| |
| static void chl_ril_dcl_changed_cb(Ubus_Data_Call_Response *dcr, int num) |
| { |
| CHL_INFO("Data call list changed. Pdp num [%d]\n", num); |
| chl_handle_dcl_changed(dcr, num); |
| } |
| |
| static int chl_ril_indication_cb(struct ubus_context *uctx, |
| struct ubus_object *obj, struct ubus_request_data *req, |
| const char *method, struct blob_attr *msg) |
| { |
| unsigned int requestid; |
| unsigned int rilerrno; |
| void *data = NULL; |
| int len, ret, num; |
| |
| ret = rilutil_parseResponse(msg, &requestid, &rilerrno, &data, &len); |
| if (ret) { |
| CHL_ERR("parse msg error\n"); |
| if(data) |
| free(data); |
| return ret; |
| } |
| |
| if (rilerrno) { |
| CHL_ERR("unsolicited id [%d], error code [%d]\n", requestid, rilerrno); |
| if(data) |
| free(data); |
| return rilerrno; |
| } |
| |
| switch (requestid) { |
| case RIL_UNSOL_VOICE_RADIO_TECH_CHANGED: |
| break; |
| case RIL_UNSOL_DATA_CALL_LIST_CHANGED: { |
| num = len / sizeof(Ubus_Data_Call_Response); |
| chl_ril_dcl_changed_cb(data, num); |
| break; |
| } |
| case RIL_UNSOL_RESPONSE_RADIO_STATE_CHANGED: |
| break; |
| case RIL_UNSOL_RESPONSE_SIM_STATUS_CHANGED: |
| break; |
| case RIL_UNSOL_SIGNAL_STRENGTH: { |
| RIL_SignalStrength_v6 *sig = (RIL_SignalStrength_v6 *)data; |
| if ((sig->GW_SignalStrength.bitErrorRate == 89) && |
| (sig->GW_SignalStrength.signalStrength == 67)) { |
| CHL_INFO("CP assert! - close all\n"); |
| chl_ps_attach_status_change(0); |
| chl_close_all(); |
| } |
| break; |
| } |
| case RIL_UNSOL_PS_ATTACH_STATUS: { |
| chl_ps_attach_status_change(*(int *)data); |
| break; |
| } |
| default: |
| break; |
| } |
| |
| if (data) |
| free(data); |
| |
| return ret; |
| } |
| |
| static int chl_ril_subscribe_indications(void) |
| { |
| int i = 0; |
| int ret = 0; |
| |
| for (i = 0; i < ARRAY_SIZE(ril_unsol_events); i++) { |
| ret = chl_ubus_subscribe_event(&ril_subscriber, |
| ril_unsol_events[i]); |
| if (ret) { |
| CHL_ERR("event [%s] subscribe failed\n", |
| ril_unsol_events[i]); |
| goto unsubscribe; |
| } |
| } |
| |
| return ret; |
| |
| unsubscribe: |
| for (i = i-1 ; i > 0; i--) |
| chl_ubus_unsubscribe_event(&ril_subscriber, ril_unsol_events[i]); |
| |
| return ret; |
| } |
| |
| static int chl_ril_unsubscribe_indications(void) |
| { |
| int i; |
| |
| for (i = 0; i < ARRAY_SIZE(ril_unsol_events); i++) |
| chl_ubus_unsubscribe_event(&ril_subscriber, ril_unsol_events[i]); |
| |
| CHL_INFO("unsubscribe ril.unsol events done\n"); |
| |
| return 0; |
| } |
| |
| int chl_ril_enable_indications(void) |
| { |
| int ret = 0; |
| |
| ret = chl_ubus_register_subscriber(&ril_subscriber); |
| if (ret) { |
| CHL_ERR("Failed to register subscriber [%s]\n", ubus_strerror(ret)); |
| return ret; |
| } |
| |
| ril_subscriber.cb = chl_ril_indication_cb; |
| |
| ret = chl_ril_subscribe_indications(); |
| if (ret) { |
| CHL_ERR("Failed to enable indications [%s]\n", ubus_strerror(ret)); |
| return ret; |
| } |
| |
| return ret; |
| } |
| |
| int chl_ril_disable_indications(void) |
| { |
| int ret = 0; |
| |
| chl_ril_unsubscribe_indications(); |
| |
| ret = chl_ubus_unregister_subscriber(&ril_subscriber); |
| if (ret) |
| CHL_ERR("Failed to unregister subscriber [%s]\n", ubus_strerror(ret)); |
| |
| return ret; |
| } |
| |
| static void chl_ril_data_cb(struct ubus_request *req, int type, |
| struct blob_attr *msg) |
| { |
| struct chl_ril_context *rctx; |
| unsigned int requestid, rilerrno = 0; |
| void *data = NULL; |
| int len = 0; |
| |
| if (rilutil_parseResponse(msg, &requestid, &rilerrno, &data, &len)) { |
| CHL_ERR("Parse failed\n"); |
| return; |
| } |
| |
| rctx = req->priv; |
| |
| if (rilerrno) { |
| rctx->ril_err = rilerrno; |
| CHL_ERR("ril request [%s] failed with [%d]\n", |
| ril_req_to_str(requestid), rilerrno); |
| if(data) |
| free(data); |
| return; |
| } |
| |
| |
| switch (requestid) { |
| case RIL_REQUEST_SETUP_DATA_CALL: { |
| rctx->dcr = data; |
| break; |
| } |
| case RIL_REQUEST_GET_PS_ATTACH_STATUS: { |
| chl_ps_attach_status_change(*(int *)data); |
| free(data); |
| break; |
| } |
| case RIL_REQUEST_GET_SIM_STATUS: { |
| RIL_CardStatus_v6 *status = data; |
| rctx->pin_status = status->applications[0].app_state; |
| free(data); |
| break; |
| } |
| case RIL_REQUEST_DATA_CALL_LIST: { |
| rctx->dcl_num = len / sizeof(Ubus_Data_Call_Response); |
| rctx->dcr = data; |
| break; |
| } |
| case RIL_REQUEST_SET_INITIAL_ATTACH_APN: |
| case RIL_REQUEST_DEACTIVATE_DATA_CALL: |
| default: |
| if (data) |
| free(data); |
| } |
| } |
| |
| static void chl_ril_complete_cb(struct ubus_request *req, int ret) |
| { |
| free(req); |
| } |
| |
| static int chl_send_to_ril(bool sync, unsigned int request, const void * data, |
| int data_len, void *priv) |
| { |
| int ret = UBUS_STATUS_OK; |
| |
| ret = blob_buf_init(&blob, 0); |
| if (ret) { |
| CHL_ERR("blob_buf_init failed: [%d] [%s]\n", ret, |
| ril_req_to_str(request)); |
| return ret; |
| } |
| |
| ret = rilutil_makeRequestBlob(&blob, request, data, data_len); |
| if (ret) { |
| CHL_ERR("rilutil_makeRequestBlob failed: [%d] [%s]", ret, |
| ril_req_to_str(request)); |
| return ret; |
| } |
| |
| if (sync) { |
| if ((ret = chl_ubus_invoke(&blob, ril_id, |
| RIL_REQ, chl_ril_data_cb, priv, |
| RIL_REQ_TIMEOUT))) |
| CHL_ERR("ubus_invoke [%s] failed: [%s]\n", |
| ril_req_to_str(request) ,ubus_strerror(ret)); |
| } else { |
| if ((ret = chl_ubus_invoke_async(&blob, ril_id, |
| RIL_REQ, chl_ril_data_cb, |
| chl_ril_complete_cb, NULL))) |
| CHL_ERR("ubus_invoke_async [%s] failed: [%s]\n", |
| ril_req_to_str(request) ,ubus_strerror(ret)); |
| } |
| |
| return ret; |
| } |
| |
| int chl_ril_setup_data_call(struct chl_pdp *pdp, bool activate, |
| Ubus_Data_Call_Response *response, int *ril_err) |
| { |
| |
| char buf[4] = {0}; |
| char auth_buf[4] = {0}; |
| char radio_buf[4] = {0}; |
| struct chl_ril_context *rctx; |
| rilutilstrings data_call; |
| int ret = 0; |
| |
| data_call.str = NULL; |
| |
| if (ril_stub) { |
| *ril_err = 0; |
| chl_ril_setup_data_call_stub(pdp, activate, response); |
| return 0; |
| } |
| |
| if (!ps_attached) { |
| *ril_err = RIL_E_OP_NOT_ALLOWED_BEFORE_REG_TO_NW; |
| return 0; |
| } |
| |
| rctx = chl_ril_context_get(); |
| |
| if (activate) { |
| data_call.num = RIL_NUM_SETUP_DATA_CALL_PARAMS; |
| data_call.str = (char **)malloc(data_call.num * sizeof(char *)); |
| |
| if (!data_call.str) { |
| CHL_ERR("string allocation failed\n"); |
| ret = -1; |
| goto done; |
| } |
| |
| if (pdp->extra.flags & EXTP_PROF) |
| sprintf(auth_buf, "%u", pdp->extra.auth_type); |
| if (pdp->extra.flags & EXTP_RADIO) |
| sprintf(radio_buf, "%u", pdp->extra.radio_tech); |
| data_call.str[0] = radio_buf; |
| data_call.str[1] = pdp->extra.data_profile; |
| data_call.str[2] = pdp->apn; |
| data_call.str[3] = pdp->extra.username; |
| data_call.str[4] = pdp->extra.password; |
| data_call.str[5] = auth_buf; |
| |
| data_call.str[6] = ril_ip_type_to_str(pdp->type); |
| |
| ret = chl_send_to_ril(true, RIL_REQUEST_SETUP_DATA_CALL, |
| &data_call, 0, rctx); |
| if (ret) { |
| CHL_ERR("chl_send_to_ril failed\n"); |
| goto done; |
| } |
| |
| if (rctx->ril_err) { |
| *ril_err= rctx->ril_err; |
| goto done; |
| } |
| |
| if (!rctx->dcr) { |
| CHL_ERR("no setup data call rsp received!\n"); |
| ret = -1; |
| goto done; |
| } |
| |
| memcpy(response, rctx->dcr, sizeof (Ubus_Data_Call_Response)); |
| } else { |
| |
| data_call.num = 2; |
| data_call.str = (char **)malloc(data_call.num * sizeof(char *)); |
| |
| if (!data_call.str) { |
| CHL_ERR("string allocation failed\n"); |
| ret = -1; |
| goto done; |
| } |
| |
| sprintf(buf, "%d", pdp->cid); |
| data_call.str[0] = buf; |
| data_call.str[1] = "0"; |
| |
| ret = chl_send_to_ril(true, RIL_REQUEST_DEACTIVATE_DATA_CALL, |
| &data_call, 0, rctx); |
| if (ret) { |
| CHL_ERR("chl_send_to_ril failed\n"); |
| ret = - 1; |
| goto done; |
| } |
| |
| if (rctx->ril_err) { |
| *ril_err = rctx->ril_err; |
| goto done; |
| } |
| |
| } |
| done: |
| chl_ril_context_done(rctx); |
| if(data_call.str) |
| free(data_call.str); |
| return ret; |
| } |
| |
| void chl_ril_request_dcl(void) |
| { |
| int ret; |
| struct chl_ril_context *rctx; |
| |
| rctx = chl_ril_context_get(); |
| |
| ret = chl_send_to_ril(true, RIL_REQUEST_DATA_CALL_LIST, NULL, 0, rctx); |
| if (ret) { |
| CHL_ERR("chl_send_to_ril failed\n"); |
| return; |
| } |
| |
| if (rctx->ril_err) { |
| CHL_ERR("failed to get data call list with [%d]\n", rctx->ril_err); |
| return; |
| } |
| |
| chl_ril_dcl_changed_cb(rctx->dcr, rctx->dcl_num); |
| |
| chl_ril_context_done(rctx); |
| } |
| |
| void chl_ril_request_ps_status(void) |
| { |
| int ret; |
| struct chl_ril_context *rctx; |
| |
| rctx = chl_ril_context_get(); |
| |
| ret = chl_send_to_ril(true, RIL_REQUEST_GET_PS_ATTACH_STATUS, NULL, 0, |
| rctx); |
| if (ret) { |
| CHL_ERR("chl_send_to_ril failed\n"); |
| return; |
| } |
| |
| if (rctx->ril_err) { |
| CHL_ERR("failed to get data ps attach status with [%d]\n", |
| rctx->ril_err); |
| return; |
| } |
| |
| chl_ril_context_done(rctx); |
| } |
| |
| int chl_ril_set_lte_dflt(struct reg_param *rp, int *ril_err) |
| { |
| struct chl_ril_context *rctx; |
| RIL_InitialAttachApn data; |
| int ret = 1, len = 0; |
| |
| memset(&data, 0, sizeof(RIL_InitialAttachApn)); |
| |
| CHL_INFO("trying to register lte default [%s]\n", rp->apn); |
| data.apn = rp->apn; |
| len += strlen(data.apn) + 1; |
| |
| data.protocol = ril_ip_type_to_str(rp->ip_type); |
| len += strlen(data.protocol) + 1; |
| |
| if (!rp->ext) |
| goto send; |
| |
| data.authtype = rp->ext->auth_type; |
| len += sizeof(data.authtype); |
| |
| if (rp->ext->flags & EXTP_UNAME) { |
| data.username = rp->ext->username; |
| len += strlen(data.username) + 1; |
| } |
| |
| if (rp->ext->flags & EXTP_PWD) { |
| data.password = rp->ext->password; |
| len += strlen(data.password) + 1; |
| } |
| |
| send: |
| rctx = chl_ril_context_get(); |
| |
| ret = chl_send_to_ril(true, RIL_REQUEST_SET_INITIAL_ATTACH_APN, &data, |
| len, rctx); |
| if (ret) { |
| CHL_ERR("chl_send_to_ril failed\n"); |
| goto done; |
| } |
| |
| if (rctx->ril_err) { |
| CHL_ERR("lte default req failed with [%d]\n", rctx->ril_err); |
| *ril_err = rctx->ril_err; |
| goto done; |
| } |
| |
| ret = 0; |
| done: |
| chl_ril_context_done(rctx); |
| return ret; |
| } |
| |
| void chl_ril_toggle_stub(void) |
| { |
| ril_stub = !ril_stub; |
| CHL_INFO("ril stub is [%s]\n", ril_stub ? "on" : "off"); |
| } |
| |
| |
| static int ril_is_ready(void) |
| { |
| if (!chl_ubus_lookup_id(RIL_NAME, &ril_id)) |
| return 1; |
| |
| return 0; |
| } |
| |
| int chl_ril_register(void) |
| { |
| int retries = 0; |
| |
| do { |
| if (ril_is_ready()) |
| goto ready; |
| sleep(1); |
| } while (retries++ < RIL_MAX_RETRIES); |
| |
| CHL_ERR("Failed to look up RIL object\n"); |
| return -1; |
| |
| ready: |
| return 0; |
| } |
| |
| static int chl_sim_is_ready(void) |
| { |
| int ret = 0; |
| struct chl_ril_context *rctx; |
| |
| rctx = chl_ril_context_get(); |
| |
| ret = chl_send_to_ril(true, RIL_REQUEST_GET_SIM_STATUS, NULL, 0, rctx); |
| if (ret) { |
| CHL_ERR("chl_send_to_ril failed\n"); |
| goto done; |
| } |
| |
| if (rctx->ril_err) { |
| CHL_ERR("sim request failed with [%d]\n", rctx->ril_err); |
| goto done; |
| } |
| |
| if (rctx->pin_status < 0 || rctx->pin_status != RIL_APPSTATE_READY) { |
| CHL_ERR("sim not ready [%d]\n", rctx->pin_status); |
| goto done; |
| } |
| |
| ret = 1; |
| done: |
| chl_ril_context_done(rctx); |
| return ret; |
| } |
| |
| int chl_wait_for_sim(void) |
| { |
| int retries = 0; |
| |
| do { |
| if (chl_sim_is_ready()) |
| goto ready; |
| sleep(1); |
| } while (retries++ < SIM_MAX_RETRIES); |
| |
| CHL_ERR("failed to wait for sim\n"); |
| return -1; |
| |
| ready: |
| return 0; |
| } |