diff options
author | PaulK <contact@paulk.fr> | 2011-11-22 21:50:42 +0100 |
---|---|---|
committer | PaulK <contact@paulk.fr> | 2011-11-22 21:50:42 +0100 |
commit | 233f0f23c75971de36d77605572c9df6b344ca73 (patch) | |
tree | 06598ad50aa97a30041d05ab9c0e8d13c797ea51 | |
parent | 791fd3e4a946c05d6598f5054075515df6327b7d (diff) | |
download | hardware_ril_samsung-ril-233f0f23c75971de36d77605572c9df6b344ca73.zip hardware_ril_samsung-ril-233f0f23c75971de36d77605572c9df6b344ca73.tar.gz hardware_ril_samsung-ril-233f0f23c75971de36d77605572c9df6b344ca73.tar.bz2 |
Modified samsung-ril to work on Nexus S.
Currently, the following is working:
* (automatic) network registration (clean and stable)
* SMS (no clean queue engine and no support for multiple message SMS)
* SIM I/O
* Other minor stuff
And the following is left to do:
* DATA (3G)
* airplane to normal power mode
* calls (including audio routing)
* RFS messages handling (mostly to be done at IPC level)
* Other minor stuff
-rw-r--r-- | Android.mk | 11 | ||||
-rw-r--r-- | disp.c | 76 | ||||
-rw-r--r-- | misc.c | 82 | ||||
-rw-r--r-- | net.c | 658 | ||||
-rw-r--r-- | pwr.c | 98 | ||||
-rw-r--r-- | samsung-ril.c | 374 | ||||
-rw-r--r-- | samsung-ril.h | 51 | ||||
-rw-r--r-- | sim.c | 20 | ||||
-rw-r--r-- | sms.c | 211 | ||||
-rw-r--r-- | util.c | 77 | ||||
-rw-r--r-- | util.h | 6 |
11 files changed, 1235 insertions, 429 deletions
@@ -12,7 +12,8 @@ LOCAL_SRC_FILES := \ sim.c \ sms.c \ util.c \ - + pwr.c \ + disp.c LOCAL_SHARED_LIBRARIES := \ libcutils libutils libril @@ -21,7 +22,15 @@ LOCAL_STATIC_LIBRARIES := libsamsung-ipc # for asprinf LOCAL_CFLAGS := -D_GNU_SOURCE +ifeq ($(TARGET_DEVICE),crespo) + LOCAL_CFLAGS += -DDEVICE_CRESPO +endif +ifeq ($(TARGET_DEVICE),h1) + LOCAL_CFLAGS += -DDEVICE_H1 +endif + LOCAL_C_INCLUDES := external/libsamsung-ipc/include +LOCAL_C_INCLUDES += hardware/ril/libsamsung-ipc/include LOCAL_MODULE_TAGS := optional @@ -0,0 +1,76 @@ +#define LOG_TAG "RIL-DISP" +#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 respondIconSignalStrength(RIL_Token t, void *data, int length) +{ + struct ipc_disp_icon_info *signal_info = (struct ipc_disp_icon_info*)data; + RIL_SignalStrength ss; + int rssi; + + /* Don't consider this if modem isn't in normal power mode. */ + if(radio.power_mode < POWER_MODE_NORMAL) + return; + + memset(&ss, 0, sizeof(ss)); + + /* Multiplying the number of bars by 3 yields + * an asu with an equal number of bars in Android + */ + rssi = (3 * signal_info->rssi); + + ss.GW_SignalStrength.signalStrength = rssi; + ss.GW_SignalStrength.bitErrorRate = 99; + + /* Send CDMA and EVDO levels even in GSM mode */ + ss.CDMA_SignalStrength.dbm = rssi; + ss.CDMA_SignalStrength.ecio = 200; + + ss.EVDO_SignalStrength.dbm = rssi; + ss.EVDO_SignalStrength.ecio = 200; + + LOGD("Signal Strength is %d\n", rssi); + + RIL_onUnsolicitedResponse(RIL_UNSOL_SIGNAL_STRENGTH, &ss, sizeof(ss)); +} + +void respondSignalStrength(RIL_Token t, void *data, int length) +{ + struct ipc_disp_rssi_info *rssi_info = (struct ipc_disp_rssi_info*)data; + RIL_SignalStrength ss; + int rssi; + + /* Don't consider this if modem isn't in normal power mode. */ + if(radio.power_mode < POWER_MODE_NORMAL) + return; + + memset(&ss, 0, sizeof(ss)); + + if(rssi_info->rssi > 0x6f) { + rssi = 0; + } else { + rssi = (((rssi_info->rssi - 0x71) * -1) - ((rssi_info->rssi - 0x71) * -1) % 2) / 2; + if(rssi > 31) + rssi = 31; + } + + /* Send CDMA and EVDO levels even in GSM mode */ + ss.GW_SignalStrength.signalStrength = rssi; + ss.GW_SignalStrength.bitErrorRate = 99; + + ss.CDMA_SignalStrength.dbm = rssi; + ss.CDMA_SignalStrength.ecio = 200; + + ss.EVDO_SignalStrength.dbm = rssi; + ss.EVDO_SignalStrength.ecio = 200; + + LOGD("Signal Strength is %d\n", rssi); + + RIL_onUnsolicitedResponse(RIL_UNSOL_SIGNAL_STRENGTH, &ss, sizeof(ss)); +} @@ -7,12 +7,92 @@ extern const struct RIL_Env *rilenv; extern struct radio_state radio; extern struct ipc_client *ipc_client; +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); +} + +// TODO: implement RIL_REQUEST_DEVICE_IDENTITY also + +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(radio.tokens.get_imei != 0 && radio.tokens.get_imei != t) + LOGE("IMEI tokens mismatch"); + + if(imei_info->length > 32) + return; + + memset(imei, 0, sizeof(imei)); + memset(imeisv, 0, sizeof(imeisv)); + + memcpy(imei, imei_info->data, imei_info->length); + + /* Last two bytes of IMEI in imei_info are the SV bytes */ + memcpy(imeisv, (imei_info->data + imei_info->length - 2), 2); + + /* IMEI */ + RIL_onRequestComplete(t, RIL_E_SUCCESS, imei, sizeof(char *)); + radio.tokens.get_imei = 0; + + /* IMEI SV */ + if(radio.tokens.get_imeisv != 0) { + RIL_onRequestComplete(radio.tokens.get_imeisv, RIL_E_SUCCESS, imeisv, sizeof(char *)); + radio.tokens.get_imeisv = 0; + } +} + +void respondMeSn(RIL_Token t, void *data, int length) +{ + struct ipc_misc_me_sn *me_sn_info; + + me_sn_info = (struct ipc_misc_me_sn *) data; + + switch(me_sn_info->type) { + case IPC_MISC_ME_SN_SERIAL_NUM: + respondIMEI(t, data, length); + break; + case IPC_MISC_ME_SN_SERIAL_NUM_SERIAL: + LOGD("Got IPC_MISC_ME_SN_SERIAL_NUM_SERIAL: %s\n", me_sn_info->data); + break; + } +} + +void requestIMEI(RIL_Token t) +{ + char data; + + if(radio.radio_state != RADIO_STATE_OFF) { + data = IPC_MISC_ME_SN_SERIAL_NUM; + + ipc_client_send(ipc_client, IPC_MISC_ME_SN, IPC_TYPE_GET, (unsigned char *) &data, sizeof(data), getRequestId(t)); + } else { + radio.tokens.get_imei = t; + } +} + +void requestIMEISV(RIL_Token t) +{ + radio.tokens.get_imeisv = t; +} + 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; + radio.tokens.baseband_version = t; } } @@ -4,62 +4,578 @@ #include "samsung-ril.h" #include "util.h" +#define RIL_TOKEN_NET_DATA_WAITING (RIL_Token) 0xff + extern const struct RIL_Env *rilenv; extern struct radio_state radio; extern struct ipc_client *ipc_client; -void requestGPRSRegistrationState(RIL_Token t) +/** + * NET Utility functions + */ + +/** + * Converts IPC network registration status to Android RIL format + */ +unsigned char reg_state_ipc2ril(unsigned char reg_state) { - struct ipc_net_regist_get message; + switch(reg_state) { + case IPC_NET_REGISTRATION_STATE_NONE: + return 0; + case IPC_NET_REGISTRATION_STATE_HOME: + return 1; + case IPC_NET_REGISTRATION_STATE_SEARCHING: + return 2; + case IPC_NET_REGISTRATION_STATE_EMERGENCY: + return 10; + case IPC_NET_REGISTRATION_STATE_ROAMING: + return 5; + case IPC_NET_REGISTRATION_STATE_UNKNOWN: + return 4; + default: + LOGE("%s: invalid reg_state: %d", __FUNCTION__, reg_state); + return 255; + } +} - /* We only support one active GPRS registration state request */ - if(!radio.token_ps) { - radio.token_ps = t; +/** + * Converts IPC network access technology to Android RIL format + */ +unsigned char act_ipc2ril(unsigned char act) +{ + switch(act) { + case IPC_NET_ACCESS_TECHNOLOGY_GPRS: + return 1; + case IPC_NET_ACCESS_TECHNOLOGY_EDGE: + return 2; + case IPC_NET_ACCESS_TECHNOLOGY_UMTS: + return 3; + case IPC_NET_ACCESS_TECHNOLOGY_GSM: + case IPC_NET_ACCESS_TECHNOLOGY_GSM2: + default: + return 0; + } +} - 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)); +/** + * Converts IPC GPRS network access technology to Android RIL format + */ +unsigned char gprs_act_ipc2ril(unsigned char act) +{ + switch(act) { + case IPC_NET_ACCESS_TECHNOLOGY_GPRS: + return 1; + case IPC_NET_ACCESS_TECHNOLOGY_EDGE: + return 2; + case IPC_NET_ACCESS_TECHNOLOGY_UMTS: + return 3; + case IPC_NET_ACCESS_TECHNOLOGY_GSM: + case IPC_NET_ACCESS_TECHNOLOGY_GSM2: + 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; + } +} + +/** + * Converts IPC PLMC to Android format + */ +void plmn_ipc2ril(struct ipc_net_current_plmn *plmndata, char *response[3]) +{ + char plmn[7]; + + memset(plmn, 0, sizeof(plmn)); + + memcpy(plmn, plmndata->plmn, 6); + + if(plmn[5] == '#') + plmn[5] = '\0'; //FIXME: remove #? + + asprintf(&response[0], "%s", plmn_lookup(plmn)); + //asprintf(&response[1], "%s", "Voda NL"); + response[1] = NULL; + asprintf(&response[2], "%s", plmn); +} + +/** + * Converts IPC reg state to Android format + */ +void reg_state_resp_ipc2ril(struct ipc_net_regist *netinfo, char *response[15]) +{ + memset(response, 0, sizeof(response)); + + asprintf(&response[0], "%d", reg_state_ipc2ril(netinfo->reg_state)); + asprintf(&response[1], "%x", netinfo->lac); + asprintf(&response[2], "%x", netinfo->cid); + asprintf(&response[3], "%d", act_ipc2ril(netinfo->act)); +} + +/** + * Converts IPC GPRS reg state to Android format + */ +void gprs_reg_state_resp_ipc2ril(struct ipc_net_regist *netinfo, char *response[4]) +{ + memset(response, 0, sizeof(response)); + + asprintf(&response[0], "%d", reg_state_ipc2ril(netinfo->reg_state)); + asprintf(&response[1], "%x", netinfo->lac); + asprintf(&response[2], "%x", netinfo->cid); + asprintf(&response[3], "%d", gprs_act_ipc2ril(netinfo->act)); +} + +/** + * Set all the tokens to data waiting. + * For instance when only operator is updated by modem NOTI, we don't need + * to ask the modem new NET Regist and GPRS Net Regist states so act like we got + * these from modem NOTI too so we don't have to make the requests + */ +void net_set_tokens_data_waiting(void) +{ + radio.tokens.registration_state = RIL_TOKEN_NET_DATA_WAITING; + radio.tokens.gprs_registration_state = RIL_TOKEN_NET_DATA_WAITING; + radio.tokens.operator = RIL_TOKEN_NET_DATA_WAITING; +} + +/** + * Returns 1 if unsol data is waiting, 0 if not + */ +int net_get_tokens_data_waiting(void) +{ + return radio.tokens.registration_state == RIL_TOKEN_NET_DATA_WAITING || radio.tokens.gprs_registration_state == RIL_TOKEN_NET_DATA_WAITING || radio.tokens.operator == RIL_TOKEN_NET_DATA_WAITING; +} + +/** + * Print net tokens values + */ +void net_tokens_state_dump(void) +{ + LOGD("NET_TOKENS_STATE_DUMP:\n\tradio.tokens.registration_state = 0x%x\n\tradio.tokens.gprs_registration_state = 0x%x\n\tradio.tokens.operator = 0x%x\n", radio.tokens.registration_state, radio.tokens.gprs_registration_state, radio.tokens.operator); +} + +/** + * How to handle NET unsol data from modem: + * 1- Rx UNSOL (NOTI) data from modem + * 2- copy data in a sized variable stored in radio + * 3- make sure no SOL request is going on for this token + * 4- copy data to radio structure + * 5- if no UNSOL data is already waiting for a token, tell RILJ NETWORK_STATE_CHANGED + * 6- set all the net tokens to RIL_TOKEN_NET_DATA_WAITING + * 7- RILJ will ask for OPERATOR, GPRS_REG_STATE and REG_STATE + * for each request: + * 8- if token is RIL_TOKEN_NET_DATA_WAITING it's SOL request for modem UNSOL data + * 9- send back modem data and tell E_SUCCESS to RILJ request + * 10- set token to 0x00 + * + * How to handle NET sol requests from RILJ: + * 1- if token is 0x00 it's UNSOL RILJ request for modem data + * 2- put RIL_Token in token + * 3- request data to the modem + * 4- Rx SOL (RESP) data from modem + * 5- copy data to radio structure + * 6- send back data to RILJ with token from modem message + * 7- if token != RIL_TOKEN_NET_DATA_WAITING, reset token to 0x00 + * + * What if both are appening at the same time? + * 1- RILJ requests modem data (UNSOL) + * 2- token is 0x00 so send request to modem + * 3- UNSOL data arrives from modem + * 4- set all tokens to RIL_TOKEN_NET_DATA_WAITING + * 5- store data, tell RILJ NETWORK_STATE_CHANGED + * 6- Rx requested data from modem + * 7- copy data to radio structure + * 8- token mismatch (is now RIL_TOKEN_NET_DATA_WAITING) + * 9- send back data to RIL with token from IPC message + * 10- don't reset token to 0x00 + * 11- RILJ does SOL request for modem data (we know it's SOL because we didn't reset token) + * 12- send back last data we have (from UNSOL RILJ request here) + */ + +/** + * In: RIL_REQUEST_OPERATOR + * Request Operator name + * + * Out: IPC_NET_CURRENT_PLMN + * return modem UNSOL data if available + * request IPC_NET_CURRENT_PLMN if no data is there + * return RIL_E_OP_NOT_ALLOWED_BEFORE_REG_TO_NW if not registered + */ +void requestOperator(RIL_Token t) +{ + char *response[3]; + int i; + + if(radio.netinfo.reg_state == IPC_NET_REGISTRATION_STATE_EMERGENCY || + radio.netinfo.reg_state == IPC_NET_REGISTRATION_STATE_NONE || + radio.netinfo.reg_state == IPC_NET_REGISTRATION_STATE_SEARCHING || + radio.netinfo.reg_state == IPC_NET_REGISTRATION_STATE_UNKNOWN) { + RIL_onRequestComplete(t, RIL_E_OP_NOT_ALLOWED_BEFORE_REG_TO_NW, NULL, 0); + + radio.tokens.operator = (RIL_Token) 0x00; + return; + } + + if(radio.tokens.operator == RIL_TOKEN_NET_DATA_WAITING) { + LOGD("Got RILJ request for UNSOL data"); + + /* Send back the data we got UNSOL */ + plmn_ipc2ril(&(radio.plmndata), response); + + RIL_onRequestComplete(t, RIL_E_SUCCESS, response, sizeof(response)); + + for(i = 0; i < sizeof(response) / sizeof(char *) ; i++) { + if(response[i] != NULL) + free(response[i]); + } + + radio.tokens.operator = (RIL_Token) 0x00; + } else if(radio.tokens.operator == (RIL_Token) 0x00) { + LOGD("Got RILJ request for SOL data"); + /* Request data to the modem */ + radio.tokens.operator = t; + + ipc_client_send_get(IPC_NET_CURRENT_PLMN, getRequestId(t)); } else { - RIL_onRequestComplete(t, RIL_E_GENERIC_FAILURE, NULL, 0); + LOGE("Another request is going on, reporting failure"); + RIL_onRequestComplete(t, RIL_E_GENERIC_FAILURE, response, sizeof(response)); } + + net_tokens_state_dump(); } -void respondGPRSRegistrationState(struct ipc_message_info *request, struct ipc_net_regist *netinfo) +/** + * In: IPC_NET_CURRENT_PLMN + * This can be SOL (RESP) or UNSOL (NOTI) message from modem + * + * Out: RIL_UNSOL_RESPONSE_NETWORK_STATE_CHANGED + * enqueue modem data if UNSOL modem message and then call + * RIL_UNSOL_RESPONSE_NETWORK_STATE_CHANGED + * if SOL message, send back data to RILJ + */ +void respondOperator(struct ipc_message_info *message) { + RIL_Token t = getToken(message->aseq); + struct ipc_net_current_plmn *plmndata = (struct ipc_net_current_plmn *) message->data; + + char *response[3]; int i; + + switch(message->type) { + case IPC_TYPE_NOTI: + LOGD("Got UNSOL Operator message"); + + if(radio.netinfo.reg_state == IPC_NET_REGISTRATION_STATE_EMERGENCY || + radio.netinfo.reg_state == IPC_NET_REGISTRATION_STATE_NONE || + radio.netinfo.reg_state == IPC_NET_REGISTRATION_STATE_SEARCHING || + radio.netinfo.reg_state == IPC_NET_REGISTRATION_STATE_UNKNOWN) { + /* Better keeping it up to date */ + memcpy(&(radio.plmndata), plmndata, sizeof(struct ipc_net_current_plmn)); + + return; + } else { + if(radio.tokens.operator != (RIL_Token) 0x00 && radio.tokens.operator != RIL_TOKEN_NET_DATA_WAITING) { + LOGE("Another Operator Req is in progress, skipping"); + return; + } + + memcpy(&(radio.plmndata), plmndata, sizeof(struct ipc_net_current_plmn)); + + /* we already told RILJ to get the new data but it wasn't done yet */ + if(net_get_tokens_data_waiting() && radio.tokens.operator == RIL_TOKEN_NET_DATA_WAITING) { + LOGD("Updating Operator data in background"); + } else { + net_set_tokens_data_waiting(); + RIL_onUnsolicitedResponse(RIL_UNSOL_RESPONSE_NETWORK_STATE_CHANGED, NULL, 0); + } + } + break; + case IPC_TYPE_RESP: + if(radio.netinfo.reg_state == IPC_NET_REGISTRATION_STATE_EMERGENCY || + radio.netinfo.reg_state == IPC_NET_REGISTRATION_STATE_NONE || + radio.netinfo.reg_state == IPC_NET_REGISTRATION_STATE_SEARCHING || + radio.netinfo.reg_state == IPC_NET_REGISTRATION_STATE_UNKNOWN) { + /* Better keeping it up to date */ + memcpy(&(radio.plmndata), plmndata, sizeof(struct ipc_net_current_plmn)); + + RIL_onRequestComplete(t, RIL_E_OP_NOT_ALLOWED_BEFORE_REG_TO_NW, NULL, 0); + + if(radio.tokens.operator != RIL_TOKEN_NET_DATA_WAITING) + radio.tokens.operator = (RIL_Token) 0x00; + return; + } else { + if(radio.tokens.operator != t) + LOGE("Operator tokens mismatch"); + + /* Better keeping it up to date */ + memcpy(&(radio.plmndata), plmndata, sizeof(struct ipc_net_current_plmn)); + + plmn_ipc2ril(plmndata, response); + + RIL_onRequestComplete(t, RIL_E_SUCCESS, response, sizeof(response)); + + for(i = 0; i < sizeof(response) / sizeof(char *) ; i++) { + if(response[i] != NULL) + free(response[i]); + } + + if(radio.tokens.operator != RIL_TOKEN_NET_DATA_WAITING) + radio.tokens.operator = (RIL_Token) 0x00; + } + break; + default: + LOGE("%s: unhandled ipc method: %d", __FUNCTION__, message->type); + break; + } + + net_tokens_state_dump(); +} + +/** + * In: RIL_REQUEST_REGISTRATION_STATE + * Request reg state + * + * Out: IPC_NET_REGIST + * return modem UNSOL data if available + * request IPC_NET_REGIST if no data is there + */ +void requestRegistrationState(RIL_Token t) +{ + struct ipc_net_regist_get regist_req; char *response[4]; + int i; - 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)); + if(radio.tokens.registration_state == RIL_TOKEN_NET_DATA_WAITING) { + LOGD("Got RILJ request for UNSOL data"); - RIL_onRequestComplete(radio.token_ps, RIL_E_SUCCESS, response, sizeof(response)); + /* Send back the data we got UNSOL */ + reg_state_resp_ipc2ril(&(radio.netinfo), response); - radio.token_ps = 0; + RIL_onRequestComplete(t, RIL_E_SUCCESS, response, sizeof(response)); - for(i = 0; i < 4; i++) { - free(response[i]); + for(i = 0; i < sizeof(response) / sizeof(char *) ; i++) { + if(response[i] != NULL) + free(response[i]); + } + + radio.tokens.registration_state = (RIL_Token) 0x00; + } else if(radio.tokens.registration_state == (RIL_Token) 0x00) { + LOGD("Got RILJ request for SOL data"); + /* Request data to the modem */ + radio.tokens.registration_state = t; + + ipc_net_regist_get(®ist_req, IPC_NET_SERVICE_DOMAIN_GSM); + ipc_client_send(ipc_client, IPC_NET_REGIST, IPC_TYPE_GET, (void *)®ist_req, sizeof(struct ipc_net_regist_get), getRequestId(t)); + } else { + LOGE("Another request is going on, reporting failure"); + RIL_onRequestComplete(t, RIL_E_GENERIC_FAILURE, NULL, 0); } + + net_tokens_state_dump(); } -void respondNetRegist(struct ipc_message_info *request) +/** + * In: RIL_REQUEST_GPRS_REGISTRATION_STATE + * Request GPRS reg state + * + * Out: IPC_NET_REGIST + * return modem UNSOL data if available + * request IPC_NET_REGIST if no data is there + */ +void requestGPRSRegistrationState(RIL_Token t) { - 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; + struct ipc_net_regist_get regist_req; + char *response[4]; + int i; - if(netinfo->domain == 3) { - LOGD("%s: netinfo service domain = ps", __FUNCTION__); - respondGPRSRegistrationState(request, netinfo); - } else { - LOGE("%s: unhandled service domain: %d", __FUNCTION__, netinfo->domain); + if(radio.tokens.gprs_registration_state == RIL_TOKEN_NET_DATA_WAITING) { + LOGD("Got RILJ request for UNSOL data"); + + /* Send back the data we got UNSOL */ + gprs_reg_state_resp_ipc2ril(&(radio.gprs_netinfo), response); + + RIL_onRequestComplete(t, RIL_E_SUCCESS, response, sizeof(response)); + + for(i = 0; i < sizeof(response) / sizeof(char *) ; i++) { + if(response[i] != NULL) + free(response[i]); } + + radio.tokens.gprs_registration_state = (RIL_Token) 0x00; + } else if(radio.tokens.gprs_registration_state == (RIL_Token) 0x00) { + LOGD("Got RILJ request for SOL data"); + + /* Request data to the modem */ + radio.tokens.gprs_registration_state = t; + + ipc_net_regist_get(®ist_req, IPC_NET_SERVICE_DOMAIN_GPRS); + ipc_client_send(ipc_client, IPC_NET_REGIST, IPC_TYPE_GET, (void *)®ist_req, sizeof(struct ipc_net_regist_get), getRequestId(t)); } else { - LOGE("%s: unhandled ipc method: %d", __FUNCTION__, request->type); + LOGE("Another request is going on, reporting failure"); + RIL_onRequestComplete(t, RIL_E_GENERIC_FAILURE, NULL, 0); + } + + net_tokens_state_dump(); +} + +void respondNetRegistUnsol(struct ipc_message_info *message) +{ + struct ipc_net_regist *netinfo; + netinfo = (struct ipc_net_regist *) message->data; + + LOGD("Got UNSOL NetRegist message"); + + switch(netinfo->domain) { + case IPC_NET_SERVICE_DOMAIN_GSM: + if(radio.tokens.registration_state != (RIL_Token) 0 && radio.tokens.registration_state != RIL_TOKEN_NET_DATA_WAITING) { + LOGE("Another NetRegist Req is in progress, skipping"); + return; + } + + memcpy(&(radio.netinfo), netinfo, sizeof(struct ipc_net_regist)); + + /* we already told RILJ to get the new data but it wasn't done yet */ + if(net_get_tokens_data_waiting() && radio.tokens.registration_state == RIL_TOKEN_NET_DATA_WAITING) { + LOGD("Updating NetRegist data in background"); + } else { + net_set_tokens_data_waiting(); + RIL_onUnsolicitedResponse(RIL_UNSOL_RESPONSE_NETWORK_STATE_CHANGED, NULL, 0); + } + break; + + case IPC_NET_SERVICE_DOMAIN_GPRS: + if(radio.tokens.gprs_registration_state != (RIL_Token) 0 && radio.tokens.gprs_registration_state != RIL_TOKEN_NET_DATA_WAITING) { + LOGE("Another GPRS NetRegist Req is in progress, skipping"); + return; + } + + memcpy(&(radio.gprs_netinfo), netinfo, sizeof(struct ipc_net_regist)); + + /* we already told RILJ to get the new data but it wasn't done yet */ + if(net_get_tokens_data_waiting() && radio.tokens.gprs_registration_state == RIL_TOKEN_NET_DATA_WAITING) { + LOGD("Updating GPRSNetRegist data in background"); + } else { + net_set_tokens_data_waiting(); + RIL_onUnsolicitedResponse(RIL_UNSOL_RESPONSE_NETWORK_STATE_CHANGED, NULL, 0); + } + break; + default: + LOGE("%s: unhandled service domain: %d", __FUNCTION__, netinfo->domain); + break; + } + + net_tokens_state_dump(); +} + +void respondNetRegistSol(struct ipc_message_info *message) +{ + char *response[4]; + int i; + + struct ipc_net_regist *netinfo = (struct ipc_net_regist *) message->data; + RIL_Token t = getToken(message->aseq); + + LOGD("Got SOL NetRegist message"); + + switch(netinfo->domain) { + case IPC_NET_SERVICE_DOMAIN_GSM: + if(radio.tokens.registration_state != t) + LOGE("Registration state tokens mismatch"); + + /* Better keeping it up to date */ + memcpy(&(radio.netinfo), netinfo, sizeof(struct ipc_net_regist)); + + reg_state_resp_ipc2ril(netinfo, response); + + RIL_onRequestComplete(t, RIL_E_SUCCESS, response, sizeof(response)); + + for(i = 0; i < sizeof(response) / sizeof(char *) ; i++) { + if(response[i] != NULL) + free(response[i]); + } + + if(radio.tokens.registration_state != RIL_TOKEN_NET_DATA_WAITING) + radio.tokens.registration_state = (RIL_Token) 0x00; + break; + case IPC_NET_SERVICE_DOMAIN_GPRS: + if(radio.tokens.gprs_registration_state != t) + LOGE("GPRS registration state tokens mismatch"); + + /* Better keeping it up to date */ + memcpy(&(radio.gprs_netinfo), netinfo, sizeof(struct ipc_net_regist)); + + gprs_reg_state_resp_ipc2ril(netinfo, response); + + RIL_onRequestComplete(t, RIL_E_SUCCESS, response, sizeof(response)); + + for(i = 0; i < sizeof(response) / sizeof(char *) ; i++) { + if(response[i] != NULL) + free(response[i]); + } + if(radio.tokens.registration_state != RIL_TOKEN_NET_DATA_WAITING) + radio.tokens.gprs_registration_state = (RIL_Token) 0x00; + break; + default: + LOGE("%s: unhandled service domain: %d", __FUNCTION__, netinfo->domain); + break; + } + + net_tokens_state_dump(); +} + +/** + * In: IPC_NET_REGIST + * This can be SOL (RESP) or UNSOL (NOTI) message from modem + */ +void respondNetRegist(struct ipc_message_info *message) +{ + /* Don't consider this if modem isn't in normal power mode. */ + if(radio.power_mode < POWER_MODE_NORMAL) + return; + + switch(message->type) { + case IPC_TYPE_NOTI: + respondNetRegistUnsol(message); + break; + case IPC_TYPE_RESP: + respondNetRegistSol(message); + break; + default: + LOGE("%s: unhandled ipc method: %d", __FUNCTION__, message->type); + break; } + } void requestGetPreferredNetworkType(RIL_Token t) @@ -82,3 +598,85 @@ void requestSetPreferredNetworkType(RIL_Token t, void *data, size_t datalen) ipc_client_send(ipc_client, IPC_NET_MODE_SEL, IPC_TYPE_SET, &ipc_mode, sizeof(ipc_mode), getRequestId(t)); } + +// FIXME: add corect implementation +void requestNwSelectionMode(RIL_Token t) +{ + unsigned int mode = 0; + RIL_onRequestComplete(t, RIL_E_SUCCESS, &mode, sizeof(mode)); +} + +/** + * In: RIL_REQUEST_QUERY_AVAILABLE_NETWORKS + * + * Out: IPC_NET_PLMN_LIST + */ +void requestAvailNetworks(RIL_Token t) +{ + ipc_client_send_get(IPC_NET_PLMN_LIST, getRequestId(t)); +} + +/* FIXME: cleanup struct names & resp[] addressing */ +/** + * In: IPC_NET_PLMN_LIST + * Send back available PLMN list + * + */ +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 = (struct ipc_net_plmn_entry *) + (data + sizeof(struct ipc_net_plmn_entries)); + + int i; + int size = (4 * entries_info->num * sizeof(char*)); + int actual_size = 0; + + char **resp = malloc(size); + char **resp_ptr = resp; +LOGE("Listed %d PLMNs\n", entries_info->num); + 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); + + LOGD("PLMN #%d: %s (%s)\n", i, plmn_lookup(plmn), 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); +} @@ -0,0 +1,98 @@ +#define LOG_TAG "RIL-PWR" +#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; + +/** + * Out: RIL_UNSOL_RESPONSE_RADIO_STATE_CHANGED + * Modem lets us know it's powered on. Though, it's still in LPM and should + * be considered as OFF. Send this to update RILJ radio state (OFF) + */ +void respondPowerUp(void) +{ + /* H1 baseband firmware bug workaround: sleep for 25ms to allow for nvram to initialize */ + usleep(25000); + + radio.radio_state = RADIO_STATE_OFF; + radio.power_mode = POWER_MODE_LPM; + RIL_onUnsolicitedResponse(RIL_UNSOL_RESPONSE_RADIO_STATE_CHANGED, NULL, 0); +} + +/** + * In: IPC_PWR_PHONE_STATE + * Noti from the modem giving current power mode (LPM or NORMAL) + * LPM = Low Power Mode (airplane mode for instance) + * + * Out: RIL_UNSOL_RESPONSE_RADIO_STATE_CHANGED + * Update radio state according to modem power state + */ +void respondPowerPhoneState(struct ipc_message_info *info) +{ + uint8_t state = *((uint8_t *)info->data); + + switch(state) + { + /* This shouldn't append for LPM (no respond message) */ + case IPC_PWR_R(IPC_PWR_PHONE_STATE_LPM): + radio.power_mode = POWER_MODE_LPM; + radio.radio_state = RADIO_STATE_OFF; + LOGD("Got power to LPM"); + RIL_onUnsolicitedResponse(RIL_UNSOL_RESPONSE_RADIO_STATE_CHANGED, NULL, 0); + break; + case IPC_PWR_R(IPC_PWR_PHONE_STATE_NORMAL): + usleep(3000); + + radio.power_mode = POWER_MODE_NORMAL; + radio.radio_state = RADIO_STATE_SIM_NOT_READY; + LOGD("Got power to NORMAL"); + + /* + * return RIL_E_SUCCESS is done at IPC_SEC_PIN_STATUS: + * breaks return-from-airplane-mode if done here + */ + RIL_onUnsolicitedResponse(RIL_UNSOL_RESPONSE_RADIO_STATE_CHANGED, NULL, 0); + break; + } + + RadioTokensCheck(); +} + +/** + * In: RIL_REQUEST_RADIO_POWER + * Request ON or OFF radio power mode + * + * Out: IPC_PWR_PHONE_STATE + * Order the modem to get in required power mode + */ +void requestPower(RIL_Token t, void *data, size_t datalen) +{ + int power_state = *((int *)data); + unsigned short power_data; + + LOGD("requested power_state is %d", power_state); + + if(power_state > 0) { + LOGD("Request power to NORMAL"); + power_data = IPC_PWR_PHONE_STATE_NORMAL; + ipc_client_send(ipc_client, IPC_PWR_PHONE_STATE, IPC_TYPE_EXEC, (void *) &power_data, sizeof(power_data), getRequestId(t)); + + radio.tokens.radio_power = t; + + /* Don't tell the RIL we're not off anymore: wait for the message */ + } else { + LOGD("Request power to LPM"); + power_data = IPC_PWR_PHONE_STATE_LPM; + ipc_client_send(ipc_client, IPC_PWR_PHONE_STATE, IPC_TYPE_EXEC, (void *) &power_data, sizeof(power_data), getRequestId(t)); + + RIL_onRequestComplete(t, RIL_E_SUCCESS, NULL, 0); + + /* We're not going to get any message to make sure we're in LPM so tell RILJ we're off anyway */ + radio_init_lpm(); + RIL_onUnsolicitedResponse(RIL_UNSOL_RESPONSE_RADIO_STATE_CHANGED, NULL, 0); + } +} diff --git a/samsung-ril.c b/samsung-ril.c index bd9bc7f..0f91378 100644 --- a/samsung-ril.c +++ b/samsung-ril.c @@ -1,3 +1,5 @@ +#include <time.h> + #include <telephony/ril.h> #include <radio.h> @@ -9,17 +11,23 @@ #include "samsung-ril.h" #include "util.h" -#define RIL_VERSION_STRING "Samsung H1 RIL" +#define RIL_VERSION_STRING "Samsung RIL" -struct radio_state radio; const struct RIL_Env *rilenv; +struct radio_state radio; + struct ipc_client *ipc_client; +int client_fmt_fd = -1; + +/* + * Token-related function + */ /* Tokens associated with requests */ RIL_Token request_ids[256]; int rid = 0; -void start_thread(); +void read_loop_thread(); int getRequestId(RIL_Token token) { @@ -42,204 +50,36 @@ RIL_Token getToken(int 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) +void RadioTokensCheck(void) { - if(radio.radio_state != RADIO_STATE_OFF) { - ipc_client_send_get(IPC_MISC_ME_SN, getRequestId(t)); - } else { - radio.token_imei = t; + if(radio.tokens.baseband_version != 0) { + if(radio.radio_state != RADIO_STATE_OFF) { + requestBasebandVersion(radio.tokens.baseband_version); + radio.tokens.baseband_version = 0; + } } -} - -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; + if(radio.tokens.get_imei != 0) { + if(radio.radio_state != RADIO_STATE_OFF) { + requestIMEI(radio.tokens.get_imei); + radio.tokens.get_imei = 0; } - - 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); - } -} +/* + * RILJ (RIL to modem) related functions + */ void onRequest(int request, void *data, size_t datalen, RIL_Token t) { //LOGD("%s: start %d %08X", __FUNCTION__, request, t); - +/* + if(radio.tokens.radio_power != 0) { + RIL_onRequestComplete(t, RIL_E_RADIO_NOT_AVAILABLE, NULL, 0); + return; + } +*/ switch(request) { case RIL_REQUEST_RADIO_POWER: requestPower(t, data, datalen); @@ -295,10 +135,10 @@ void onRequest(int request, void *data, size_t datalen, RIL_Token t) requestSendSms(t, data, datalen); break; case RIL_REQUEST_SEND_SMS_EXPECT_MORE: - requestSendSms(t, data, datalen); + requestSendSmsExpectMore(t, data, datalen); break; case RIL_REQUEST_SMS_ACKNOWLEDGE: - requestSmsAcknowledge(t); + requestSmsAcknowledge(t, data, datalen); break; case RIL_REQUEST_GET_SIM_STATUS: requestSimStatus(t); @@ -324,6 +164,11 @@ void onRequest(int request, void *data, size_t datalen, RIL_Token t) case RIL_REQUEST_STK_HANDLE_CALL_SETUP_REQUESTED_FROM_SIM: RIL_onRequestComplete(t, RIL_E_SUCCESS, NULL, 0); break; + case RIL_REQUEST_SCREEN_STATE: + /* This doesn't affect anything */ + 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); @@ -354,23 +199,6 @@ 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; @@ -383,16 +211,23 @@ void respondGenPhonRes(struct ipc_message_info *info) } } +/** + * libsamsung-ipc (modem to RIL) related functions + */ + 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); + // TODO: add IPC_NET_SERVING_NETWORK + 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(); + respondPowerUp(); + break; + case IPC_PWR_PHONE_STATE: + respondPowerPhoneState(info); break; case IPC_MISC_ME_VERSION: respondBasebandVersion(info); @@ -401,13 +236,13 @@ void onReceive(struct ipc_message_info *info) respondIMSI(info); break; case IPC_MISC_ME_SN: - respondIMEI(t, info->data, info->length); + respondMeSn(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); + respondOperator(info); break; case IPC_NET_PLMN_LIST: respondAvailNetworks(t, info->data, info->length); @@ -419,6 +254,9 @@ void onReceive(struct ipc_message_info *info) respondModeSel(info); break; case IPC_DISP_ICON_INFO: + respondIconSignalStrength(t, info->data, info->length); + break; + case IPC_DISP_RSSI_INFO: respondSignalStrength(t, info->data, info->length); break; case IPC_CALL_INCOMING: @@ -433,6 +271,15 @@ void onReceive(struct ipc_message_info *info) case IPC_SMS_INCOMING_MSG: respondSmsIncoming(t, info->data, info->length); break; + case IPC_SMS_DELIVER_REPORT: + respondSmsDeliverReport(t, info->data, info->length); + break; + case IPC_SMS_SVC_CENTER_ADDR: + respondSmsSvcCenterAddr(t, info->data, info->length); + break; + case IPC_SMS_SEND_MSG: + respondSmsSendMsg(t, info->data, info->length); + break; case IPC_SEC_PIN_STATUS: respondSimStatusChanged(t, info->data, info->length); break; @@ -454,6 +301,9 @@ void onReceive(struct ipc_message_info *info) case IPC_GEN_PHONE_RES: respondGenPhonRes(info); break; + case IPC_SMS_DEVICE_READY: + respondSmsDeviceReady(t, info); + break; default: //LOGD("Unknown msgtype: %04x", info->type); break; @@ -465,52 +315,69 @@ void ipc_log_handler(const char *message, void *user_data) LOGD("ipc: %s", message); } -void *init_loop() +/** + * read_loop(): + * This function is the main IPC read loop + */ +void *read_loop() { struct ipc_message_info resp; + fd_set fds; - 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); + FD_ZERO(&fds); + FD_SET(client_fmt_fd, &fds); - if(ipc_client_open(ipc_client)) { - LOGE("%s: failed to open ipc client", __FUNCTION__); - return 0; - } + while(1) { + usleep(3000); - if(ipc_client_power_on(ipc_client)) { - LOGE("%s: failed to power on ipc client", __FUNCTION__); - return 0; - } + select(client_fmt_fd + 1, &fds, NULL, NULL, NULL); - while(1) { - ipc_client_recv(ipc_client, &resp); + if(FD_ISSET(client_fmt_fd, &fds)) { + if(ipc_client_recv(ipc_client, &resp)) { + LOGE("IPC RECV failure!!!"); + break; + } + LOGD("RECV aseq=0x%x mseq=0x%x data_length=%d\n", resp.aseq, resp.mseq, resp.length); - onReceive(&resp); + onReceive(&resp); - if(resp.data != NULL) - free(resp.data); + 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() +void radio_init_tokens(void) +{ + memset(&(radio.tokens), 0, sizeof(struct ril_tokens)); +} + +void radio_init_lpm(void) +{ + memset(&radio, 0, sizeof(radio)); + radio.radio_state = RADIO_STATE_OFF; + radio.power_mode = POWER_MODE_LPM; +} + +void read_loop_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); + pthread_create(&thread, &attr, read_loop, NULL); } +/** + * RIL_Init function + */ + static const RIL_RadioFunctions radio_ops = { RIL_VERSION, onRequest, @@ -522,13 +389,40 @@ static const RIL_RadioFunctions radio_ops = { 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; + radio_init_lpm(); + radio_init_tokens(); rilenv = env; + LOGD("Creating new FMT client"); + 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); + + LOGD("All handlers data is %p", &client_fmt_fd); + ipc_client_set_all_handlers_data(ipc_client, &client_fmt_fd); + + LOGD("Client open..."); + if(ipc_client_open(ipc_client)) { + LOGE("%s: failed to open ipc client", __FUNCTION__); + return 0; + } + + if(client_fmt_fd < 0) { + LOGE("%s: client_fmt_fd is negative, aborting", __FUNCTION__); + return 0; + } + + LOGD("Client power on..."); + if(ipc_client_power_on(ipc_client)) { + LOGE("%s: failed to power on ipc client", __FUNCTION__); + return 0; + } + + read_loop_thread(); + return &radio_ops; } diff --git a/samsung-ril.h b/samsung-ril.h index cf91cb4..c13686f 100644 --- a/samsung-ril.h +++ b/samsung-ril.h @@ -27,27 +27,49 @@ typedef enum { SIM_SERVICE_PROVIDER_PERSO = 9, } SIM_Status; +typedef enum { + POWER_MODE_LPM = 0, + POWER_MODE_NORMAL = 2, + POWER_MODE_SIM_INIT_COMPLETE = 4, +} Modem_PowerMode; + +// Move RIL_Token token_ps, token_cs; here +struct ril_tokens { + RIL_Token radio_power; + RIL_Token get_imei; + RIL_Token get_imeisv; + RIL_Token baseband_version; + + RIL_Token registration_state; + RIL_Token gprs_registration_state; + RIL_Token operator; + + RIL_Token send_sms; +}; + + struct radio_state { RIL_RadioState radio_state; RIL_CardState card_state; + SIM_Status sim_status; + Modem_PowerMode power_mode; - RIL_Token token_imei; - RIL_Token token_imeisv; - - RIL_Token token_baseband_ver; + struct ril_tokens tokens; struct ipc_net_regist netinfo; + struct ipc_net_regist gprs_netinfo; + struct ipc_net_current_plmn plmndata; - /* 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; + unsigned char msg_tpid_lock; + char *msg_pdu; }; +void RadioTokensCheck(void); int getRequestId(RIL_Token token); RIL_Token getToken(int id); +void radio_init_lpm(void); + /* Call */ void requestCallList(RIL_Token t); void requestGetCurrentCalls(RIL_Token t); @@ -92,8 +114,17 @@ 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 requestSmsAcknowledge(RIL_Token t, void *data, size_t datalen); +void respondSmsDeviceReady(RIL_Token t, struct ipc_message_info *info); void requestIMSI(RIL_Token t); void respondIMSI(struct ipc_message_info *request); +/* PWR */ +void respondPowerUp(void); +void respondPowerPhoneState(struct ipc_message_info *info); +void requestPower(RIL_Token t, void *data, size_t datalen); + +/* DISP */ +void respondIconSignalStrength(RIL_Token t, void *data, int length); +void respondSignalStrength(RIL_Token t, void *data, int length); @@ -17,6 +17,10 @@ extern struct ipc_client *ipc_client; */ void updateRadioState(SIM_Status status) { + /* If power mode isn't at least normal, don't update RIL state */ + if(radio.power_mode < POWER_MODE_NORMAL) + return; + switch(status) { case SIM_READY: radio.radio_state = RADIO_STATE_SIM_READY; @@ -39,6 +43,7 @@ void updateRadioState(SIM_Status status) break; } + RadioTokensCheck(); RIL_onUnsolicitedResponse(RIL_UNSOL_RESPONSE_RADIO_STATE_CHANGED, NULL, 0); } @@ -58,6 +63,15 @@ void respondSimStatusChanged(RIL_Token t, void *data, int length) { struct ipc_sec_pin_status_noti *pin_status = (struct ipc_sec_pin_status_noti*)data; + /* Don't consider this if modem isn't in normal power mode. */ + if(radio.power_mode < POWER_MODE_NORMAL) + return; + + if(radio.power_mode == POWER_MODE_NORMAL && radio.tokens.radio_power != 0) { + RIL_onRequestComplete(radio.tokens.radio_power, RIL_E_SUCCESS, NULL, 0); + radio.tokens.radio_power = 0; + } + /* Determine SIM status */ switch(pin_status->type) { case IPC_SEC_PIN_SIM_INITIALIZING: @@ -340,11 +354,7 @@ void requestEnterSimPin(RIL_Token t, void *data, size_t datalen) 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_sec_pin_status_set_setup(&pin_status, IPC_SEC_PIN_TYPE_PIN1, pin, NULL); ipc_client_send_set(IPC_SEC_PIN_STATUS, getRequestId(t), (unsigned char*)&pin_status, sizeof(pin_status)); @@ -11,18 +11,21 @@ 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)); + 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; + int resp_length = info->length * 2 + 1; char *resp = (char*)malloc(resp_length); - bin2hex(pdu, length, resp); + bin2hex(pdu, info->length, resp); + LOGD("PDU string is '%s'\n", resp); + + if(radio.msg_tpid_lock != 0) { + LOGE("Another message is already waiting for ACK, aborting"); + //FIXME: it would be cleaner to enqueue it + goto exit; + } + + radio.msg_tpid_lock = info->msg_tpid; if(info->type == IPC_SMS_TYPE_POINT_TO_POINT) { RIL_onUnsolicitedResponse(RIL_UNSOL_RESPONSE_NEW_SMS, resp, resp_length); @@ -32,70 +35,89 @@ void respondSmsIncoming(RIL_Token t, void *data, int length) LOGE("%s: Unknown message type", __FUNCTION__); } +exit: 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) +void requestSendSms(RIL_Token t, void *data, size_t datalen) { - 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); + const char **request; + request = (char **) data; + int pdu_len = strlen(request[1]); - length = sizeof(struct ipc_sms_send_msg) + sc_length + data_length; + /* We first need to get SMS SVC before sending the message */ - buf = (unsigned char*)malloc(length); - memset(buf, 0, length); - p = buf; + if(request[0] == NULL) { + LOGD("We have no SMSC, asking one before anything"); - /* First, setup the header required by IPC */ - msg = (struct ipc_sms_send_msg*)p; - msg->hint = hint; - msg->length = sc_length + data_length; + if(radio.tokens.send_sms != 0 && radio.msg_pdu != NULL) { + LOGE("Another message is being sent, aborting"); + //FIXME: it would be cleaner to enqueue it + } - p += sizeof(struct ipc_sms_send_msg); + radio.tokens.send_sms = t; + radio.msg_pdu = malloc(pdu_len); + memcpy(radio.msg_pdu, request[1], pdu_len); - /* Add SC data */ - if(sc_length > 1) { - hex2bin(request[0], strlen(request[0]), p); + ipc_client_send_get(IPC_SMS_SVC_CENTER_ADDR, getRequestId(t)); + } else { - *p = 0x00; + sms_send_msg(t, request[1], request[0]); } +} + +void sms_send_msg(RIL_Token t, char *pdu, char *smsc_string) +{ + char *data; + char *p; + struct ipc_sms_send_msg send_msg; + char *decoded_pdu; - p += sc_length; + int pdu_str_len = strlen(pdu); + int pdu_len = pdu_str_len / 2; + int smsc_len = smsc_string[0]; + int send_msg_len = sizeof(struct ipc_sms_send_msg); + int length = pdu_len + smsc_len + send_msg_len; - /* Add SMS PDU data */ - hex2bin(request[1], strlen(request[1]), p); + LOGD("Sending SMS message!"); - /* FIXME: ipc_sms_send_msg(buf, length, getRequestId(t)); */ - LOGE("%s: missing impl", __FUNCTION__); + LOGD("length is %x + %x + %x = 0x%x\n", pdu_len, smsc_len, send_msg_len, length); - /* FIXME: Move to baseband response handler */ - RIL_onRequestComplete(t, RIL_E_SUCCESS, NULL, 0); + decoded_pdu = malloc(pdu_len); + hex2bin(pdu, pdu_str_len, decoded_pdu); + + data = malloc(length); + memset(&send_msg, 0, sizeof(struct ipc_sms_send_msg)); + + send_msg.type = IPC_SMS_TYPE_OUTGOING; + send_msg.msg_type = IPC_SMS_MSG_SINGLE; //fixme: define based on PDU + send_msg.length = (unsigned char) length; + send_msg.smsc_len = (unsigned char) smsc_len; + + p = data; - free(buf); + memcpy(p, &send_msg, send_msg_len); + p += send_msg_len; + memcpy(p, (char *) (smsc_string + 1), smsc_len); + p += smsc_len; + memcpy(p, decoded_pdu, pdu_len); + + ipc_client_send(ipc_client, IPC_SMS_SEND_MSG, IPC_TYPE_EXEC, data, length, getRequestId(t)); + + /* Wait for ACK to return to RILJ */ + radio.tokens.send_sms = t; + + free(decoded_pdu); + free(data); } -/** - * In: RIL_REQUEST_SEND_SMS - * Send an SMS message - * - * Out: IPC_SMS_SEND_MSG - */ -void requestSendSms(RIL_Token t, void *data, size_t datalen) +void respondSmsSvcCenterAddr(RIL_Token t, void *data, size_t datalen) { - requestSendSmsEx(t, data, datalen, IPC_SMS_MSG_SINGLE); + if(radio.tokens.send_sms == t && radio.msg_pdu != NULL) { + sms_send_msg(t, radio.msg_pdu, data); + + free(radio.msg_pdu); + } } /** @@ -108,7 +130,51 @@ void requestSendSms(RIL_Token t, void *data, size_t datalen) */ void requestSendSmsExpectMore(RIL_Token t, void *data, size_t datalen) { - requestSendSmsEx(t, data, datalen, IPC_SMS_MSG_MULTIPLE); + /* FIXME: We seriously need a decent queue here */ + +} + +unsigned short sms_ack_error_ril2ipc(int success, int failcause) +{ + if(success) { + return IPC_SMS_ACK_NO_ERROR; + } else { + switch(failcause) { + case 0xD3: + return IPC_SMS_ACK_PDA_FULL_ERROR; + default: + return IPC_SMS_ACK_UNSPEC_ERROR; + } + } +} + +RIL_Errno sms_ack_error_ipc2ril(unsigned short error) +{ + switch(error) { + case IPC_SMS_ACK_NO_ERROR: + return RIL_E_SUCCESS; + default: + return RIL_E_GENERIC_FAILURE; + } +} + +void respondSmsSendMsg(RIL_Token t, void *data, size_t datalen) +{ + struct ipc_sms_deliv_report_msg *report_msg = data; + RIL_Errno ril_ack_err; + + if(radio.tokens.send_sms != t) { + LOGE("Wrong token to ACK"); + } + + LOGD("RECV ack for msg_tpid %d\n", report_msg->msg_tpid); + + ril_ack_err = sms_ack_error_ipc2ril(report_msg->error); + + radio.tokens.send_sms = 0; + + RIL_onRequestComplete(t, ril_ack_err, NULL, 0); + } /** @@ -119,12 +185,39 @@ void requestSendSmsExpectMore(RIL_Token t, void *data, size_t datalen) * Out: IPC_SMS_DELIVER_REPORT * Sends a SMS delivery report */ -void requestSmsAcknowledge(RIL_Token t) +void requestSmsAcknowledge(RIL_Token t, void *data, size_t datalen) +{ + struct ipc_sms_deliv_report_msg report_msg; + int success = ((int *)data)[0]; + int failcause = ((int *)data)[1]; + + if(radio.msg_tpid_lock == 0) { + LOGE("No stored msg_tpid, aborting\n"); + return; + } + + report_msg.type = IPC_SMS_TYPE_STATUS_REPORT; + report_msg.error = sms_ack_error_ril2ipc(success, failcause); + report_msg.msg_tpid = radio.msg_tpid_lock; + report_msg.unk = 0; + + radio.msg_tpid_lock = 0; + + ipc_client_send(ipc_client, IPC_SMS_DELIVER_REPORT, IPC_TYPE_EXEC, (void *) &report_msg, sizeof(struct ipc_sms_deliv_report_msg), getRequestId(t)); +} + +void respondSmsDeliverReport(RIL_Token t, void *data, size_t datalen) { - /* FIXME ipc_sms_deliver_report(getRequestId(t)); */ - LOGE("%s: missing impl", __FUNCTION__); + //FIXME: check it's alright from data (or not, no need to check the ACK of our ACK) - /* FIXME: Move to baseband response handler */ RIL_onRequestComplete(t, RIL_E_SUCCESS, NULL, 0); } +void respondSmsDeviceReady(RIL_Token t, struct ipc_message_info *info) +{ + if(radio.radio_state == RADIO_STATE_SIM_READY) { + ipc_client_send(ipc_client, IPC_SMS_DEVICE_READY, IPC_TYPE_SET, NULL, 0, getRequestId(t)); + } + + RadioTokensCheck(); +} @@ -57,80 +57,3 @@ void bin2hex(const unsigned char *data, int length, char *buf) *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; - } -} - @@ -1,8 +1,2 @@ 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); - |