blob: c081ccfb151ac8e44f489d63db41c2a0302dd86f [file] [log] [blame]
The Android Open Source Project00f06fc2009-03-03 19:32:15 -08001/* //device/system/reference-ril/reference-ril.c
2**
3** Copyright 2006, The Android Open Source Project
4**
5** Licensed under the Apache License, Version 2.0 (the "License");
6** you may not use this file except in compliance with the License.
7** You may obtain a copy of the License at
8**
9** http://www.apache.org/licenses/LICENSE-2.0
10**
11** Unless required by applicable law or agreed to in writing, software
12** distributed under the License is distributed on an "AS IS" BASIS,
13** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14** See the License for the specific language governing permissions and
15** limitations under the License.
16*/
17
Jaime A Lopez-Sollanoe9645042012-08-29 07:27:27 -070018#include <telephony/ril_cdma_sms.h>
Wink Saville8a9e0212013-04-09 12:11:38 -070019#include <telephony/librilutils.h>
David 'Digit' Turner834eca82016-06-22 12:10:01 +020020#include <stdbool.h>
The Android Open Source Project00f06fc2009-03-03 19:32:15 -080021#include <stdio.h>
22#include <assert.h>
23#include <string.h>
24#include <errno.h>
25#include <unistd.h>
Mark Salyzynba58c202014-03-12 15:20:22 -070026#include <sys/cdefs.h>
The Android Open Source Project00f06fc2009-03-03 19:32:15 -080027#include <sys/types.h>
28#include <sys/stat.h>
29#include <fcntl.h>
30#include <pthread.h>
31#include <alloca.h>
32#include "atchannel.h"
33#include "at_tok.h"
34#include "misc.h"
35#include <getopt.h>
36#include <sys/socket.h>
37#include <cutils/sockets.h>
38#include <termios.h>
David 'Digit' Turneraf1298d2011-02-04 13:36:47 +010039#include <sys/system_properties.h>
David 'Digit' Turner2e98d892016-06-16 19:00:05 +020040#include <system/qemu_pipe.h>
The Android Open Source Project00f06fc2009-03-03 19:32:15 -080041
Wink Saville9a9fbd22011-02-15 17:13:10 -080042#include "ril.h"
43
The Android Open Source Project00f06fc2009-03-03 19:32:15 -080044#define LOG_TAG "RIL"
45#include <utils/Log.h>
46
Etan Cohend3652192014-06-20 08:28:44 -070047static void *noopRemoveWarning( void *a ) { return a; }
48#define RIL_UNUSED_PARM(a) noopRemoveWarning((void *)&(a));
49
The Android Open Source Project00f06fc2009-03-03 19:32:15 -080050#define MAX_AT_RESPONSE 0x1000
51
Wink Savillef4c4d362009-04-02 01:37:03 -070052/* pathname returned from RIL_REQUEST_SETUP_DATA_CALL / RIL_REQUEST_SETUP_DEFAULT_PDP */
Robert Greenwaltf838ede2010-07-15 18:54:53 -070053#define PPP_TTY_PATH "eth0"
The Android Open Source Project00f06fc2009-03-03 19:32:15 -080054
Sukanya Rajkhowab44dda32014-06-02 14:03:44 -070055// Default MTU value
56#define DEFAULT_MTU 1500
57
The Android Open Source Project00f06fc2009-03-03 19:32:15 -080058#ifdef USE_TI_COMMANDS
59
60// Enable a workaround
61// 1) Make incoming call, do not answer
62// 2) Hangup remote end
63// Expected: call should disappear from CLCC line
64// Actual: Call shows as "ACTIVE" before disappearing
65#define WORKAROUND_ERRONEOUS_ANSWER 1
66
67// Some varients of the TI stack do not support the +CGEV unsolicited
68// response. However, they seem to send an unsolicited +CME ERROR: 150
69#define WORKAROUND_FAKE_CGEV 1
70#endif
71
Jaime A Lopez-Sollanoe9645042012-08-29 07:27:27 -070072/* Modem Technology bits */
73#define MDM_GSM 0x01
74#define MDM_WCDMA 0x02
75#define MDM_CDMA 0x04
76#define MDM_EVDO 0x08
77#define MDM_LTE 0x10
78
79typedef struct {
80 int supportedTechs; // Bitmask of supported Modem Technology bits
81 int currentTech; // Technology the modem is currently using (in the format used by modem)
82 int isMultimode;
83
84 // Preferred mode bitmask. This is actually 4 byte-sized bitmasks with different priority values,
85 // in which the byte number from LSB to MSB give the priority.
86 //
87 // |MSB| | |LSB
88 // value: |00 |00 |00 |00
89 // byte #: |3 |2 |1 |0
90 //
91 // Higher byte order give higher priority. Thus, a value of 0x0000000f represents
92 // a preferred mode of GSM, WCDMA, CDMA, and EvDo in which all are equally preferrable, whereas
93 // 0x00000201 represents a mode with GSM and WCDMA, in which WCDMA is preferred over GSM
94 int32_t preferredNetworkMode;
95 int subscription_source;
96
97} ModemInfo;
98
99static ModemInfo *sMdmInfo;
100// TECH returns the current technology in the format used by the modem.
101// It can be used as an l-value
102#define TECH(mdminfo) ((mdminfo)->currentTech)
103// TECH_BIT returns the bitmask equivalent of the current tech
104#define TECH_BIT(mdminfo) (1 << ((mdminfo)->currentTech))
105#define IS_MULTIMODE(mdminfo) ((mdminfo)->isMultimode)
106#define TECH_SUPPORTED(mdminfo, tech) ((mdminfo)->supportedTechs & (tech))
107#define PREFERRED_NETWORK(mdminfo) ((mdminfo)->preferredNetworkMode)
108// CDMA Subscription Source
109#define SSOURCE(mdminfo) ((mdminfo)->subscription_source)
110
111static int net2modem[] = {
112 MDM_GSM | MDM_WCDMA, // 0 - GSM / WCDMA Pref
113 MDM_GSM, // 1 - GSM only
114 MDM_WCDMA, // 2 - WCDMA only
115 MDM_GSM | MDM_WCDMA, // 3 - GSM / WCDMA Auto
116 MDM_CDMA | MDM_EVDO, // 4 - CDMA / EvDo Auto
117 MDM_CDMA, // 5 - CDMA only
118 MDM_EVDO, // 6 - EvDo only
119 MDM_GSM | MDM_WCDMA | MDM_CDMA | MDM_EVDO, // 7 - GSM/WCDMA, CDMA, EvDo
120 MDM_LTE | MDM_CDMA | MDM_EVDO, // 8 - LTE, CDMA and EvDo
121 MDM_LTE | MDM_GSM | MDM_WCDMA, // 9 - LTE, GSM/WCDMA
122 MDM_LTE | MDM_CDMA | MDM_EVDO | MDM_GSM | MDM_WCDMA, // 10 - LTE, CDMA, EvDo, GSM/WCDMA
123 MDM_LTE, // 11 - LTE only
124};
125
126static int32_t net2pmask[] = {
127 MDM_GSM | (MDM_WCDMA << 8), // 0 - GSM / WCDMA Pref
128 MDM_GSM, // 1 - GSM only
129 MDM_WCDMA, // 2 - WCDMA only
130 MDM_GSM | MDM_WCDMA, // 3 - GSM / WCDMA Auto
131 MDM_CDMA | MDM_EVDO, // 4 - CDMA / EvDo Auto
132 MDM_CDMA, // 5 - CDMA only
133 MDM_EVDO, // 6 - EvDo only
134 MDM_GSM | MDM_WCDMA | MDM_CDMA | MDM_EVDO, // 7 - GSM/WCDMA, CDMA, EvDo
135 MDM_LTE | MDM_CDMA | MDM_EVDO, // 8 - LTE, CDMA and EvDo
136 MDM_LTE | MDM_GSM | MDM_WCDMA, // 9 - LTE, GSM/WCDMA
137 MDM_LTE | MDM_CDMA | MDM_EVDO | MDM_GSM | MDM_WCDMA, // 10 - LTE, CDMA, EvDo, GSM/WCDMA
138 MDM_LTE, // 11 - LTE only
139};
140
141static int is3gpp2(int radioTech) {
142 switch (radioTech) {
143 case RADIO_TECH_IS95A:
144 case RADIO_TECH_IS95B:
145 case RADIO_TECH_1xRTT:
146 case RADIO_TECH_EVDO_0:
147 case RADIO_TECH_EVDO_A:
148 case RADIO_TECH_EVDO_B:
149 case RADIO_TECH_EHRPD:
150 return 1;
151 default:
152 return 0;
153 }
154}
155
John Wang309ac292009-07-30 14:53:23 -0700156typedef enum {
157 SIM_ABSENT = 0,
158 SIM_NOT_READY = 1,
159 SIM_READY = 2, /* SIM_READY means the radio state is RADIO_STATE_SIM_READY */
160 SIM_PIN = 3,
161 SIM_PUK = 4,
Jaime A Lopez-Sollanoe9645042012-08-29 07:27:27 -0700162 SIM_NETWORK_PERSONALIZATION = 5,
163 RUIM_ABSENT = 6,
164 RUIM_NOT_READY = 7,
165 RUIM_READY = 8,
166 RUIM_PIN = 9,
167 RUIM_PUK = 10,
168 RUIM_NETWORK_PERSONALIZATION = 11
David 'Digit' Turneraf1298d2011-02-04 13:36:47 +0100169} SIM_Status;
John Wang309ac292009-07-30 14:53:23 -0700170
The Android Open Source Project00f06fc2009-03-03 19:32:15 -0800171static void onRequest (int request, void *data, size_t datalen, RIL_Token t);
172static RIL_RadioState currentState();
173static int onSupports (int requestCode);
174static void onCancel (RIL_Token t);
175static const char *getVersion();
176static int isRadioOn();
John Wang309ac292009-07-30 14:53:23 -0700177static SIM_Status getSIMStatus();
Wink Saville2c1fb3a2011-03-19 13:42:45 -0700178static int getCardStatus(RIL_CardStatus_v6 **pp_card_status);
179static void freeCardStatus(RIL_CardStatus_v6 *p_card_status);
Wink Savillef4c4d362009-04-02 01:37:03 -0700180static void onDataCallListChanged(void *param);
The Android Open Source Project00f06fc2009-03-03 19:32:15 -0800181
182extern const char * requestToString(int request);
183
184/*** Static Variables ***/
185static const RIL_RadioFunctions s_callbacks = {
186 RIL_VERSION,
187 onRequest,
188 currentState,
189 onSupports,
190 onCancel,
191 getVersion
192};
193
194#ifdef RIL_SHLIB
195static const struct RIL_Env *s_rilenv;
196
197#define RIL_onRequestComplete(t, e, response, responselen) s_rilenv->OnRequestComplete(t,e, response, responselen)
198#define RIL_onUnsolicitedResponse(a,b,c) s_rilenv->OnUnsolicitedResponse(a,b,c)
199#define RIL_requestTimedCallback(a,b,c) s_rilenv->RequestTimedCallback(a,b,c)
200#endif
201
202static RIL_RadioState sState = RADIO_STATE_UNAVAILABLE;
203
204static pthread_mutex_t s_state_mutex = PTHREAD_MUTEX_INITIALIZER;
205static pthread_cond_t s_state_cond = PTHREAD_COND_INITIALIZER;
206
207static int s_port = -1;
208static const char * s_device_path = NULL;
209static int s_device_socket = 0;
210
211/* trigger change to this with s_state_cond */
212static int s_closed = 0;
213
214static int sFD; /* file desc of AT channel */
215static char sATBuffer[MAX_AT_RESPONSE+1];
216static char *sATBufferCur = NULL;
217
218static const struct timeval TIMEVAL_SIMPOLL = {1,0};
219static const struct timeval TIMEVAL_CALLSTATEPOLL = {0,500000};
220static const struct timeval TIMEVAL_0 = {0,0};
221
Sukanya Rajkhowaa18b9d12013-09-10 12:30:13 -0700222static int s_ims_registered = 0; // 0==unregistered
223static int s_ims_services = 1; // & 0x1 == sms over ims supported
224static int s_ims_format = 1; // FORMAT_3GPP(1) vs FORMAT_3GPP2(2);
225static int s_ims_cause_retry = 0; // 1==causes sms over ims to temp fail
226static int s_ims_cause_perm_failure = 0; // 1==causes sms over ims to permanent fail
227static int s_ims_gsm_retry = 0; // 1==causes sms over gsm to temp fail
228static int s_ims_gsm_fail = 0; // 1==causes sms over gsm to permanent fail
229
The Android Open Source Project00f06fc2009-03-03 19:32:15 -0800230#ifdef WORKAROUND_ERRONEOUS_ANSWER
231// Max number of times we'll try to repoll when we think
232// we have a AT+CLCC race condition
233#define REPOLL_CALLS_COUNT_MAX 4
234
235// Line index that was incoming or waiting at last poll, or -1 for none
236static int s_incomingOrWaitingLine = -1;
237// Number of times we've asked for a repoll of AT+CLCC
238static int s_repollCallsCount = 0;
239// Should we expect a call to be answered in the next CLCC?
240static int s_expectAnswer = 0;
241#endif /* WORKAROUND_ERRONEOUS_ANSWER */
242
David 'Digit' Turner834eca82016-06-22 12:10:01 +0200243// Returns true iff running this process in an emulator VM
244static bool isInEmulator(void) {
245 static int inQemu = -1;
246 if (inQemu < 0) {
247 char propValue[PROP_VALUE_MAX];
248 inQemu = (__system_property_get("ro.kernel.qemu", propValue) != 0);
249 }
250 return inQemu == 1;
251}
252
Wink Saville8a9e0212013-04-09 12:11:38 -0700253static int s_cell_info_rate_ms = INT_MAX;
254static int s_mcc = 0;
255static int s_mnc = 0;
256static int s_lac = 0;
257static int s_cid = 0;
258
The Android Open Source Project00f06fc2009-03-03 19:32:15 -0800259static void pollSIMState (void *param);
260static void setRadioState(RIL_RadioState newState);
Jaime A Lopez-Sollanoe9645042012-08-29 07:27:27 -0700261static void setRadioTechnology(ModemInfo *mdm, int newtech);
262static int query_ctec(ModemInfo *mdm, int *current, int32_t *preferred);
263static int parse_technology_response(const char *response, int *current, int32_t *preferred);
264static int techFromModemType(int mdmtype);
The Android Open Source Project00f06fc2009-03-03 19:32:15 -0800265
266static int clccStateToRILState(int state, RIL_CallState *p_state)
267
268{
269 switch(state) {
270 case 0: *p_state = RIL_CALL_ACTIVE; return 0;
271 case 1: *p_state = RIL_CALL_HOLDING; return 0;
272 case 2: *p_state = RIL_CALL_DIALING; return 0;
273 case 3: *p_state = RIL_CALL_ALERTING; return 0;
274 case 4: *p_state = RIL_CALL_INCOMING; return 0;
275 case 5: *p_state = RIL_CALL_WAITING; return 0;
276 default: return -1;
277 }
278}
279
280/**
281 * Note: directly modified line and has *p_call point directly into
282 * modified line
283 */
Wink Saville3d54e742009-05-18 18:00:44 -0700284static int callFromCLCCLine(char *line, RIL_Call *p_call)
The Android Open Source Project00f06fc2009-03-03 19:32:15 -0800285{
286 //+CLCC: 1,0,2,0,0,\"+18005551212\",145
287 // index,isMT,state,mode,isMpty(,number,TOA)?
288
289 int err;
290 int state;
291 int mode;
292
293 err = at_tok_start(&line);
294 if (err < 0) goto error;
295
296 err = at_tok_nextint(&line, &(p_call->index));
297 if (err < 0) goto error;
298
299 err = at_tok_nextbool(&line, &(p_call->isMT));
300 if (err < 0) goto error;
301
302 err = at_tok_nextint(&line, &state);
303 if (err < 0) goto error;
304
305 err = clccStateToRILState(state, &(p_call->state));
306 if (err < 0) goto error;
307
308 err = at_tok_nextint(&line, &mode);
309 if (err < 0) goto error;
310
311 p_call->isVoice = (mode == 0);
312
313 err = at_tok_nextbool(&line, &(p_call->isMpty));
314 if (err < 0) goto error;
315
316 if (at_tok_hasmore(&line)) {
317 err = at_tok_nextstr(&line, &(p_call->number));
318
319 /* tolerate null here */
320 if (err < 0) return 0;
321
322 // Some lame implementations return strings
323 // like "NOT AVAILABLE" in the CLCC line
324 if (p_call->number != NULL
325 && 0 == strspn(p_call->number, "+0123456789")
326 ) {
327 p_call->number = NULL;
328 }
329
330 err = at_tok_nextint(&line, &p_call->toa);
331 if (err < 0) goto error;
332 }
333
Wink Saville74fa3882009-12-22 15:35:41 -0800334 p_call->uusInfo = NULL;
335
The Android Open Source Project00f06fc2009-03-03 19:32:15 -0800336 return 0;
337
338error:
Wink Saville4dcab4f2012-11-19 16:05:13 -0800339 RLOGE("invalid CLCC line\n");
The Android Open Source Project00f06fc2009-03-03 19:32:15 -0800340 return -1;
341}
342
343
344/** do post-AT+CFUN=1 initialization */
345static void onRadioPowerOn()
346{
347#ifdef USE_TI_COMMANDS
348 /* Must be after CFUN=1 */
349 /* TI specific -- notifications for CPHS things such */
350 /* as CPHS message waiting indicator */
351
352 at_send_command("AT%CPHS=1", NULL);
353
354 /* TI specific -- enable NITZ unsol notifs */
355 at_send_command("AT%CTZV=1", NULL);
356#endif
357
358 pollSIMState(NULL);
359}
360
361/** do post- SIM ready initialization */
362static void onSIMReady()
363{
364 at_send_command_singleline("AT+CSMS=1", "+CSMS:", NULL);
365 /*
366 * Always send SMS messages directly to the TE
367 *
368 * mode = 1 // discard when link is reserved (link should never be
369 * reserved)
370 * mt = 2 // most messages routed to TE
371 * bm = 2 // new cell BM's routed to TE
372 * ds = 1 // Status reports routed to TE
373 * bfr = 1 // flush buffer
374 */
375 at_send_command("AT+CNMI=1,2,2,1,1", NULL);
376}
377
Sanket Padawef0c8ca72016-06-30 15:01:08 -0700378static void requestRadioPower(void *data, size_t datalen __unused, RIL_Token t)
The Android Open Source Project00f06fc2009-03-03 19:32:15 -0800379{
380 int onOff;
381
382 int err;
383 ATResponse *p_response = NULL;
384
385 assert (datalen >= sizeof(int *));
386 onOff = ((int *)data)[0];
387
388 if (onOff == 0 && sState != RADIO_STATE_OFF) {
389 err = at_send_command("AT+CFUN=0", &p_response);
390 if (err < 0 || p_response->success == 0) goto error;
391 setRadioState(RADIO_STATE_OFF);
392 } else if (onOff > 0 && sState == RADIO_STATE_OFF) {
393 err = at_send_command("AT+CFUN=1", &p_response);
394 if (err < 0|| p_response->success == 0) {
395 // Some stacks return an error when there is no SIM,
396 // but they really turn the RF portion on
397 // So, if we get an error, let's check to see if it
398 // turned on anyway
399
400 if (isRadioOn() != 1) {
401 goto error;
402 }
403 }
Jaime A Lopez-Sollanoe9645042012-08-29 07:27:27 -0700404 setRadioState(RADIO_STATE_ON);
The Android Open Source Project00f06fc2009-03-03 19:32:15 -0800405 }
406
407 at_response_free(p_response);
408 RIL_onRequestComplete(t, RIL_E_SUCCESS, NULL, 0);
409 return;
410error:
411 at_response_free(p_response);
412 RIL_onRequestComplete(t, RIL_E_GENERIC_FAILURE, NULL, 0);
413}
414
Naveen Kallaa65a16a2014-07-31 16:48:31 -0700415static void requestShutdown(RIL_Token t)
416{
417 int onOff;
418
419 int err;
420 ATResponse *p_response = NULL;
421
422 if (sState != RADIO_STATE_OFF) {
423 err = at_send_command("AT+CFUN=0", &p_response);
424 setRadioState(RADIO_STATE_UNAVAILABLE);
425 }
426
427 at_response_free(p_response);
428 RIL_onRequestComplete(t, RIL_E_SUCCESS, NULL, 0);
429 return;
430}
431
Wink Savillef4c4d362009-04-02 01:37:03 -0700432static void requestOrSendDataCallList(RIL_Token *t);
The Android Open Source Project00f06fc2009-03-03 19:32:15 -0800433
Mark Salyzynba58c202014-03-12 15:20:22 -0700434static void onDataCallListChanged(void *param __unused)
The Android Open Source Project00f06fc2009-03-03 19:32:15 -0800435{
Wink Savillef4c4d362009-04-02 01:37:03 -0700436 requestOrSendDataCallList(NULL);
The Android Open Source Project00f06fc2009-03-03 19:32:15 -0800437}
438
Mark Salyzynba58c202014-03-12 15:20:22 -0700439static void requestDataCallList(void *data __unused, size_t datalen __unused, RIL_Token t)
The Android Open Source Project00f06fc2009-03-03 19:32:15 -0800440{
Wink Savillef4c4d362009-04-02 01:37:03 -0700441 requestOrSendDataCallList(&t);
The Android Open Source Project00f06fc2009-03-03 19:32:15 -0800442}
443
Wink Savillef4c4d362009-04-02 01:37:03 -0700444static void requestOrSendDataCallList(RIL_Token *t)
The Android Open Source Project00f06fc2009-03-03 19:32:15 -0800445{
446 ATResponse *p_response;
447 ATLine *p_cur;
448 int err;
449 int n = 0;
450 char *out;
451
452 err = at_send_command_multiline ("AT+CGACT?", "+CGACT:", &p_response);
453 if (err != 0 || p_response->success == 0) {
454 if (t != NULL)
455 RIL_onRequestComplete(*t, RIL_E_GENERIC_FAILURE, NULL, 0);
456 else
Wink Savillef4c4d362009-04-02 01:37:03 -0700457 RIL_onUnsolicitedResponse(RIL_UNSOL_DATA_CALL_LIST_CHANGED,
The Android Open Source Project00f06fc2009-03-03 19:32:15 -0800458 NULL, 0);
459 return;
460 }
461
462 for (p_cur = p_response->p_intermediates; p_cur != NULL;
463 p_cur = p_cur->p_next)
464 n++;
465
Sukanya Rajkhowab44dda32014-06-02 14:03:44 -0700466 RIL_Data_Call_Response_v11 *responses =
467 alloca(n * sizeof(RIL_Data_Call_Response_v11));
The Android Open Source Project00f06fc2009-03-03 19:32:15 -0800468
469 int i;
470 for (i = 0; i < n; i++) {
Wink Saville43808972011-01-13 17:39:51 -0800471 responses[i].status = -1;
Wink Saville250eb3c2011-06-22 09:11:34 -0700472 responses[i].suggestedRetryTime = -1;
The Android Open Source Project00f06fc2009-03-03 19:32:15 -0800473 responses[i].cid = -1;
474 responses[i].active = -1;
475 responses[i].type = "";
Wink Saville43808972011-01-13 17:39:51 -0800476 responses[i].ifname = "";
477 responses[i].addresses = "";
478 responses[i].dnses = "";
Wink Saville2c1fb3a2011-03-19 13:42:45 -0700479 responses[i].gateways = "";
Etan Cohend3652192014-06-20 08:28:44 -0700480 responses[i].pcscf = "";
Sukanya Rajkhowab44dda32014-06-02 14:03:44 -0700481 responses[i].mtu = 0;
The Android Open Source Project00f06fc2009-03-03 19:32:15 -0800482 }
483
Sukanya Rajkhowab44dda32014-06-02 14:03:44 -0700484 RIL_Data_Call_Response_v11 *response = responses;
The Android Open Source Project00f06fc2009-03-03 19:32:15 -0800485 for (p_cur = p_response->p_intermediates; p_cur != NULL;
486 p_cur = p_cur->p_next) {
487 char *line = p_cur->line;
488
489 err = at_tok_start(&line);
490 if (err < 0)
491 goto error;
492
493 err = at_tok_nextint(&line, &response->cid);
494 if (err < 0)
495 goto error;
496
497 err = at_tok_nextint(&line, &response->active);
498 if (err < 0)
499 goto error;
500
501 response++;
502 }
503
504 at_response_free(p_response);
505
506 err = at_send_command_multiline ("AT+CGDCONT?", "+CGDCONT:", &p_response);
507 if (err != 0 || p_response->success == 0) {
508 if (t != NULL)
509 RIL_onRequestComplete(*t, RIL_E_GENERIC_FAILURE, NULL, 0);
510 else
Wink Savillef4c4d362009-04-02 01:37:03 -0700511 RIL_onUnsolicitedResponse(RIL_UNSOL_DATA_CALL_LIST_CHANGED,
The Android Open Source Project00f06fc2009-03-03 19:32:15 -0800512 NULL, 0);
513 return;
514 }
515
516 for (p_cur = p_response->p_intermediates; p_cur != NULL;
517 p_cur = p_cur->p_next) {
518 char *line = p_cur->line;
519 int cid;
The Android Open Source Project00f06fc2009-03-03 19:32:15 -0800520
521 err = at_tok_start(&line);
522 if (err < 0)
523 goto error;
524
525 err = at_tok_nextint(&line, &cid);
526 if (err < 0)
527 goto error;
528
529 for (i = 0; i < n; i++) {
530 if (responses[i].cid == cid)
531 break;
532 }
533
534 if (i >= n) {
535 /* details for a context we didn't hear about in the last request */
536 continue;
537 }
538
Wink Saville43808972011-01-13 17:39:51 -0800539 // Assume no error
540 responses[i].status = 0;
541
542 // type
The Android Open Source Project00f06fc2009-03-03 19:32:15 -0800543 err = at_tok_nextstr(&line, &out);
544 if (err < 0)
545 goto error;
The Android Open Source Project00f06fc2009-03-03 19:32:15 -0800546 responses[i].type = alloca(strlen(out) + 1);
547 strcpy(responses[i].type, out);
548
Wink Saville43808972011-01-13 17:39:51 -0800549 // APN ignored for v5
The Android Open Source Project00f06fc2009-03-03 19:32:15 -0800550 err = at_tok_nextstr(&line, &out);
551 if (err < 0)
552 goto error;
553
Wink Saville43808972011-01-13 17:39:51 -0800554 responses[i].ifname = alloca(strlen(PPP_TTY_PATH) + 1);
555 strcpy(responses[i].ifname, PPP_TTY_PATH);
The Android Open Source Project00f06fc2009-03-03 19:32:15 -0800556
557 err = at_tok_nextstr(&line, &out);
558 if (err < 0)
559 goto error;
560
Wink Saville43808972011-01-13 17:39:51 -0800561 responses[i].addresses = alloca(strlen(out) + 1);
562 strcpy(responses[i].addresses, out);
563
David 'Digit' Turner834eca82016-06-22 12:10:01 +0200564 if (isInEmulator()) {
565 /* We are in the emulator - the dns servers are listed
566 * by the following system properties, setup in
567 * /system/etc/init.goldfish.sh:
568 * - net.eth0.dns1
569 * - net.eth0.dns2
570 * - net.eth0.dns3
571 * - net.eth0.dns4
572 */
573 const int dnslist_sz = 128;
574 char* dnslist = alloca(dnslist_sz);
575 const char* separator = "";
576 int nn;
David 'Digit' Turneraf1298d2011-02-04 13:36:47 +0100577
David 'Digit' Turner834eca82016-06-22 12:10:01 +0200578 dnslist[0] = 0;
579 for (nn = 1; nn <= 4; nn++) {
580 /* Probe net.eth0.dns<n> */
581 char propName[PROP_NAME_MAX];
582 char propValue[PROP_VALUE_MAX];
David 'Digit' Turneraf1298d2011-02-04 13:36:47 +0100583
David 'Digit' Turner834eca82016-06-22 12:10:01 +0200584 snprintf(propName, sizeof propName, "net.eth0.dns%d", nn);
David 'Digit' Turneraf1298d2011-02-04 13:36:47 +0100585
David 'Digit' Turner834eca82016-06-22 12:10:01 +0200586 /* Ignore if undefined */
587 if (__system_property_get(propName, propValue) == 0) {
588 continue;
David 'Digit' Turneraf1298d2011-02-04 13:36:47 +0100589 }
Wink Saville2c1fb3a2011-03-19 13:42:45 -0700590
David 'Digit' Turner834eca82016-06-22 12:10:01 +0200591 /* Append the DNS IP address */
592 strlcat(dnslist, separator, dnslist_sz);
593 strlcat(dnslist, propValue, dnslist_sz);
594 separator = " ";
David 'Digit' Turneraf1298d2011-02-04 13:36:47 +0100595 }
David 'Digit' Turner834eca82016-06-22 12:10:01 +0200596 responses[i].dnses = dnslist;
597
598 /* There is only on gateway in the emulator */
599 responses[i].gateways = "10.0.2.2";
600 responses[i].mtu = DEFAULT_MTU;
601 }
602 else {
603 /* I don't know where we are, so use the public Google DNS
604 * servers by default and no gateway.
605 */
606 responses[i].dnses = "8.8.8.8 8.8.4.4";
607 responses[i].gateways = "";
David 'Digit' Turneraf1298d2011-02-04 13:36:47 +0100608 }
The Android Open Source Project00f06fc2009-03-03 19:32:15 -0800609 }
610
611 at_response_free(p_response);
612
613 if (t != NULL)
614 RIL_onRequestComplete(*t, RIL_E_SUCCESS, responses,
Sukanya Rajkhowab44dda32014-06-02 14:03:44 -0700615 n * sizeof(RIL_Data_Call_Response_v11));
The Android Open Source Project00f06fc2009-03-03 19:32:15 -0800616 else
Wink Savillef4c4d362009-04-02 01:37:03 -0700617 RIL_onUnsolicitedResponse(RIL_UNSOL_DATA_CALL_LIST_CHANGED,
The Android Open Source Project00f06fc2009-03-03 19:32:15 -0800618 responses,
Sukanya Rajkhowab44dda32014-06-02 14:03:44 -0700619 n * sizeof(RIL_Data_Call_Response_v11));
The Android Open Source Project00f06fc2009-03-03 19:32:15 -0800620
621 return;
622
623error:
624 if (t != NULL)
625 RIL_onRequestComplete(*t, RIL_E_GENERIC_FAILURE, NULL, 0);
626 else
Wink Savillef4c4d362009-04-02 01:37:03 -0700627 RIL_onUnsolicitedResponse(RIL_UNSOL_DATA_CALL_LIST_CHANGED,
The Android Open Source Project00f06fc2009-03-03 19:32:15 -0800628 NULL, 0);
629
630 at_response_free(p_response);
631}
632
633static void requestQueryNetworkSelectionMode(
Mark Salyzynba58c202014-03-12 15:20:22 -0700634 void *data __unused, size_t datalen __unused, RIL_Token t)
The Android Open Source Project00f06fc2009-03-03 19:32:15 -0800635{
636 int err;
637 ATResponse *p_response = NULL;
638 int response = 0;
639 char *line;
640
641 err = at_send_command_singleline("AT+COPS?", "+COPS:", &p_response);
642
643 if (err < 0 || p_response->success == 0) {
644 goto error;
645 }
646
647 line = p_response->p_intermediates->line;
648
649 err = at_tok_start(&line);
650
651 if (err < 0) {
652 goto error;
653 }
654
655 err = at_tok_nextint(&line, &response);
656
657 if (err < 0) {
658 goto error;
659 }
660
661 RIL_onRequestComplete(t, RIL_E_SUCCESS, &response, sizeof(int));
662 at_response_free(p_response);
663 return;
664error:
665 at_response_free(p_response);
Wink Saville4dcab4f2012-11-19 16:05:13 -0800666 RLOGE("requestQueryNetworkSelectionMode must never return error when radio is on");
The Android Open Source Project00f06fc2009-03-03 19:32:15 -0800667 RIL_onRequestComplete(t, RIL_E_GENERIC_FAILURE, NULL, 0);
668}
669
Mark Salyzynba58c202014-03-12 15:20:22 -0700670static void sendCallStateChanged(void *param __unused)
The Android Open Source Project00f06fc2009-03-03 19:32:15 -0800671{
672 RIL_onUnsolicitedResponse (
673 RIL_UNSOL_RESPONSE_CALL_STATE_CHANGED,
674 NULL, 0);
675}
676
Mark Salyzynba58c202014-03-12 15:20:22 -0700677static void requestGetCurrentCalls(void *data __unused, size_t datalen __unused, RIL_Token t)
The Android Open Source Project00f06fc2009-03-03 19:32:15 -0800678{
679 int err;
680 ATResponse *p_response;
681 ATLine *p_cur;
682 int countCalls;
683 int countValidCalls;
Wink Saville3d54e742009-05-18 18:00:44 -0700684 RIL_Call *p_calls;
685 RIL_Call **pp_calls;
The Android Open Source Project00f06fc2009-03-03 19:32:15 -0800686 int i;
687 int needRepoll = 0;
688
689#ifdef WORKAROUND_ERRONEOUS_ANSWER
690 int prevIncomingOrWaitingLine;
691
692 prevIncomingOrWaitingLine = s_incomingOrWaitingLine;
693 s_incomingOrWaitingLine = -1;
694#endif /*WORKAROUND_ERRONEOUS_ANSWER*/
695
696 err = at_send_command_multiline ("AT+CLCC", "+CLCC:", &p_response);
697
698 if (err != 0 || p_response->success == 0) {
699 RIL_onRequestComplete(t, RIL_E_GENERIC_FAILURE, NULL, 0);
700 return;
701 }
702
703 /* count the calls */
704 for (countCalls = 0, p_cur = p_response->p_intermediates
705 ; p_cur != NULL
706 ; p_cur = p_cur->p_next
707 ) {
708 countCalls++;
709 }
710
711 /* yes, there's an array of pointers and then an array of structures */
712
Wink Saville3d54e742009-05-18 18:00:44 -0700713 pp_calls = (RIL_Call **)alloca(countCalls * sizeof(RIL_Call *));
714 p_calls = (RIL_Call *)alloca(countCalls * sizeof(RIL_Call));
715 memset (p_calls, 0, countCalls * sizeof(RIL_Call));
The Android Open Source Project00f06fc2009-03-03 19:32:15 -0800716
717 /* init the pointer array */
718 for(i = 0; i < countCalls ; i++) {
719 pp_calls[i] = &(p_calls[i]);
720 }
721
722 for (countValidCalls = 0, p_cur = p_response->p_intermediates
723 ; p_cur != NULL
724 ; p_cur = p_cur->p_next
725 ) {
726 err = callFromCLCCLine(p_cur->line, p_calls + countValidCalls);
727
728 if (err != 0) {
729 continue;
730 }
731
732#ifdef WORKAROUND_ERRONEOUS_ANSWER
733 if (p_calls[countValidCalls].state == RIL_CALL_INCOMING
734 || p_calls[countValidCalls].state == RIL_CALL_WAITING
735 ) {
736 s_incomingOrWaitingLine = p_calls[countValidCalls].index;
737 }
738#endif /*WORKAROUND_ERRONEOUS_ANSWER*/
739
740 if (p_calls[countValidCalls].state != RIL_CALL_ACTIVE
741 && p_calls[countValidCalls].state != RIL_CALL_HOLDING
742 ) {
743 needRepoll = 1;
744 }
745
746 countValidCalls++;
747 }
748
749#ifdef WORKAROUND_ERRONEOUS_ANSWER
750 // Basically:
751 // A call was incoming or waiting
752 // Now it's marked as active
753 // But we never answered it
754 //
755 // This is probably a bug, and the call will probably
756 // disappear from the call list in the next poll
757 if (prevIncomingOrWaitingLine >= 0
758 && s_incomingOrWaitingLine < 0
759 && s_expectAnswer == 0
760 ) {
761 for (i = 0; i < countValidCalls ; i++) {
762
763 if (p_calls[i].index == prevIncomingOrWaitingLine
764 && p_calls[i].state == RIL_CALL_ACTIVE
765 && s_repollCallsCount < REPOLL_CALLS_COUNT_MAX
766 ) {
Wink Saville4dcab4f2012-11-19 16:05:13 -0800767 RLOGI(
The Android Open Source Project00f06fc2009-03-03 19:32:15 -0800768 "Hit WORKAROUND_ERRONOUS_ANSWER case."
769 " Repoll count: %d\n", s_repollCallsCount);
770 s_repollCallsCount++;
771 goto error;
772 }
773 }
774 }
775
776 s_expectAnswer = 0;
777 s_repollCallsCount = 0;
778#endif /*WORKAROUND_ERRONEOUS_ANSWER*/
779
Wink Saville3d54e742009-05-18 18:00:44 -0700780 RIL_onRequestComplete(t, RIL_E_SUCCESS, pp_calls,
781 countValidCalls * sizeof (RIL_Call *));
The Android Open Source Project00f06fc2009-03-03 19:32:15 -0800782
783 at_response_free(p_response);
784
785#ifdef POLL_CALL_STATE
786 if (countValidCalls) { // We don't seem to get a "NO CARRIER" message from
787 // smd, so we're forced to poll until the call ends.
788#else
789 if (needRepoll) {
790#endif
791 RIL_requestTimedCallback (sendCallStateChanged, NULL, &TIMEVAL_CALLSTATEPOLL);
792 }
793
794 return;
795error:
796 RIL_onRequestComplete(t, RIL_E_GENERIC_FAILURE, NULL, 0);
797 at_response_free(p_response);
798}
799
Mark Salyzynba58c202014-03-12 15:20:22 -0700800static void requestDial(void *data, size_t datalen __unused, RIL_Token t)
The Android Open Source Project00f06fc2009-03-03 19:32:15 -0800801{
802 RIL_Dial *p_dial;
803 char *cmd;
804 const char *clir;
805 int ret;
806
807 p_dial = (RIL_Dial *)data;
808
809 switch (p_dial->clir) {
810 case 1: clir = "I"; break; /*invocation*/
811 case 2: clir = "i"; break; /*suppression*/
812 default:
813 case 0: clir = ""; break; /*subscription default*/
814 }
815
816 asprintf(&cmd, "ATD%s%s;", p_dial->address, clir);
817
818 ret = at_send_command(cmd, NULL);
819
820 free(cmd);
821
822 /* success or failure is ignored by the upper layer here.
823 it will call GET_CURRENT_CALLS and determine success that way */
824 RIL_onRequestComplete(t, RIL_E_SUCCESS, NULL, 0);
825}
826
Mark Salyzynba58c202014-03-12 15:20:22 -0700827static void requestWriteSmsToSim(void *data, size_t datalen __unused, RIL_Token t)
The Android Open Source Project00f06fc2009-03-03 19:32:15 -0800828{
829 RIL_SMS_WriteArgs *p_args;
830 char *cmd;
831 int length;
832 int err;
833 ATResponse *p_response = NULL;
834
835 p_args = (RIL_SMS_WriteArgs *)data;
836
837 length = strlen(p_args->pdu)/2;
838 asprintf(&cmd, "AT+CMGW=%d,%d", length, p_args->status);
839
840 err = at_send_command_sms(cmd, p_args->pdu, "+CMGW:", &p_response);
841
842 if (err != 0 || p_response->success == 0) goto error;
843
844 RIL_onRequestComplete(t, RIL_E_SUCCESS, NULL, 0);
845 at_response_free(p_response);
846
847 return;
848error:
849 RIL_onRequestComplete(t, RIL_E_GENERIC_FAILURE, NULL, 0);
850 at_response_free(p_response);
851}
852
Mark Salyzynba58c202014-03-12 15:20:22 -0700853static void requestHangup(void *data, size_t datalen __unused, RIL_Token t)
The Android Open Source Project00f06fc2009-03-03 19:32:15 -0800854{
855 int *p_line;
856
857 int ret;
858 char *cmd;
859
860 p_line = (int *)data;
861
862 // 3GPP 22.030 6.5.5
863 // "Releases a specific active call X"
864 asprintf(&cmd, "AT+CHLD=1%d", p_line[0]);
865
866 ret = at_send_command(cmd, NULL);
867
868 free(cmd);
869
870 /* success or failure is ignored by the upper layer here.
871 it will call GET_CURRENT_CALLS and determine success that way */
872 RIL_onRequestComplete(t, RIL_E_SUCCESS, NULL, 0);
873}
874
Mark Salyzynba58c202014-03-12 15:20:22 -0700875static void requestSignalStrength(void *data __unused, size_t datalen __unused, RIL_Token t)
The Android Open Source Project00f06fc2009-03-03 19:32:15 -0800876{
877 ATResponse *p_response = NULL;
878 int err;
The Android Open Source Project00f06fc2009-03-03 19:32:15 -0800879 char *line;
Uma Maheswari Ramalingam9efcac52012-08-09 11:59:17 -0700880 int count =0;
881 int numofElements=sizeof(RIL_SignalStrength_v6)/sizeof(int);
882 int response[numofElements];
The Android Open Source Project00f06fc2009-03-03 19:32:15 -0800883
884 err = at_send_command_singleline("AT+CSQ", "+CSQ:", &p_response);
885
886 if (err < 0 || p_response->success == 0) {
887 RIL_onRequestComplete(t, RIL_E_GENERIC_FAILURE, NULL, 0);
888 goto error;
889 }
890
891 line = p_response->p_intermediates->line;
892
893 err = at_tok_start(&line);
894 if (err < 0) goto error;
895
Uma Maheswari Ramalingam9efcac52012-08-09 11:59:17 -0700896 for (count =0; count < numofElements; count ++) {
897 err = at_tok_nextint(&line, &(response[count]));
898 if (err < 0) goto error;
899 }
Chih-Wei Huang28059052012-04-30 01:13:27 +0800900
Uma Maheswari Ramalingam9efcac52012-08-09 11:59:17 -0700901 RIL_onRequestComplete(t, RIL_E_SUCCESS, response, sizeof(response));
The Android Open Source Project00f06fc2009-03-03 19:32:15 -0800902
903 at_response_free(p_response);
904 return;
905
906error:
Wink Saville4dcab4f2012-11-19 16:05:13 -0800907 RLOGE("requestSignalStrength must never return an error when radio is on");
The Android Open Source Project00f06fc2009-03-03 19:32:15 -0800908 RIL_onRequestComplete(t, RIL_E_GENERIC_FAILURE, NULL, 0);
909 at_response_free(p_response);
910}
911
Jaime A Lopez-Sollanoe9645042012-08-29 07:27:27 -0700912/**
913 * networkModePossible. Decides whether the network mode is appropriate for the
914 * specified modem
915 */
916static int networkModePossible(ModemInfo *mdm, int nm)
917{
918 if ((net2modem[nm] & mdm->supportedTechs) == net2modem[nm]) {
919 return 1;
920 }
921 return 0;
922}
Mark Salyzynba58c202014-03-12 15:20:22 -0700923static void requestSetPreferredNetworkType( int request __unused, void *data,
924 size_t datalen __unused, RIL_Token t )
Jaime A Lopez-Sollanoe9645042012-08-29 07:27:27 -0700925{
926 ATResponse *p_response = NULL;
927 char *cmd = NULL;
928 int value = *(int *)data;
929 int current, old;
930 int err;
931 int32_t preferred = net2pmask[value];
932
Wink Saville4dcab4f2012-11-19 16:05:13 -0800933 RLOGD("requestSetPreferredNetworkType: current: %x. New: %x", PREFERRED_NETWORK(sMdmInfo), preferred);
Jaime A Lopez-Sollanoe9645042012-08-29 07:27:27 -0700934 if (!networkModePossible(sMdmInfo, value)) {
935 RIL_onRequestComplete(t, RIL_E_MODE_NOT_SUPPORTED, NULL, 0);
936 return;
937 }
938 if (query_ctec(sMdmInfo, &current, NULL) < 0) {
939 RIL_onRequestComplete(t, RIL_E_GENERIC_FAILURE, NULL, 0);
940 return;
941 }
942 old = PREFERRED_NETWORK(sMdmInfo);
Wink Saville4dcab4f2012-11-19 16:05:13 -0800943 RLOGD("old != preferred: %d", old != preferred);
Jaime A Lopez-Sollanoe9645042012-08-29 07:27:27 -0700944 if (old != preferred) {
945 asprintf(&cmd, "AT+CTEC=%d,\"%x\"", current, preferred);
Wink Saville4dcab4f2012-11-19 16:05:13 -0800946 RLOGD("Sending command: <%s>", cmd);
Jaime A Lopez-Sollanoe9645042012-08-29 07:27:27 -0700947 err = at_send_command_singleline(cmd, "+CTEC:", &p_response);
948 free(cmd);
949 if (err || !p_response->success) {
950 RIL_onRequestComplete(t, RIL_E_GENERIC_FAILURE, NULL, 0);
951 return;
952 }
953 PREFERRED_NETWORK(sMdmInfo) = value;
954 if (!strstr( p_response->p_intermediates->line, "DONE") ) {
955 int current;
956 int res = parse_technology_response(p_response->p_intermediates->line, &current, NULL);
957 switch (res) {
958 case -1: // Error or unable to parse
959 break;
960 case 1: // Only able to parse current
961 case 0: // Both current and preferred were parsed
962 setRadioTechnology(sMdmInfo, current);
963 break;
964 }
965 }
966 }
967 RIL_onRequestComplete(t, RIL_E_SUCCESS, NULL, 0);
968}
969
Mark Salyzynba58c202014-03-12 15:20:22 -0700970static void requestGetPreferredNetworkType(int request __unused, void *data __unused,
971 size_t datalen __unused, RIL_Token t)
Jaime A Lopez-Sollanoe9645042012-08-29 07:27:27 -0700972{
973 int preferred;
974 unsigned i;
975
976 switch ( query_ctec(sMdmInfo, NULL, &preferred) ) {
977 case -1: // Error or unable to parse
978 case 1: // Only able to parse current
979 RIL_onRequestComplete(t, RIL_E_GENERIC_FAILURE, NULL, 0);
980 break;
981 case 0: // Both current and preferred were parsed
982 for ( i = 0 ; i < sizeof(net2pmask) / sizeof(int32_t) ; i++ ) {
983 if (preferred == net2pmask[i]) {
984 RIL_onRequestComplete(t, RIL_E_SUCCESS, &i, sizeof(int));
985 return;
986 }
987 }
Wink Saville4dcab4f2012-11-19 16:05:13 -0800988 RLOGE("Unknown preferred mode received from modem: %d", preferred);
Jaime A Lopez-Sollanoe9645042012-08-29 07:27:27 -0700989 RIL_onRequestComplete(t, RIL_E_GENERIC_FAILURE, NULL, 0);
990 break;
991 }
992
993}
994
Mark Salyzynba58c202014-03-12 15:20:22 -0700995static void requestCdmaPrlVersion(int request __unused, void *data __unused,
996 size_t datalen __unused, RIL_Token t)
Jaime A Lopez-Sollanoe9645042012-08-29 07:27:27 -0700997{
998 int err;
999 char * responseStr;
1000 ATResponse *p_response = NULL;
1001 const char *cmd;
1002 char *line;
1003
1004 err = at_send_command_singleline("AT+WPRL?", "+WPRL:", &p_response);
1005 if (err < 0 || !p_response->success) goto error;
1006 line = p_response->p_intermediates->line;
1007 err = at_tok_start(&line);
1008 if (err < 0) goto error;
1009 err = at_tok_nextstr(&line, &responseStr);
1010 if (err < 0 || !responseStr) goto error;
1011 RIL_onRequestComplete(t, RIL_E_SUCCESS, responseStr, strlen(responseStr));
1012 at_response_free(p_response);
1013 return;
1014error:
1015 at_response_free(p_response);
1016 RIL_onRequestComplete(t, RIL_E_GENERIC_FAILURE, NULL, 0);
1017}
1018
Mark Salyzynba58c202014-03-12 15:20:22 -07001019static void requestCdmaBaseBandVersion(int request __unused, void *data __unused,
1020 size_t datalen __unused, RIL_Token t)
Jaime A Lopez-Sollanoe9645042012-08-29 07:27:27 -07001021{
1022 int err;
1023 char * responseStr;
1024 ATResponse *p_response = NULL;
1025 const char *cmd;
1026 const char *prefix;
1027 char *line, *p;
1028 int commas;
1029 int skip;
1030 int count = 4;
1031
1032 // Fixed values. TODO: query modem
1033 responseStr = strdup("1.0.0.0");
1034 RIL_onRequestComplete(t, RIL_E_SUCCESS, responseStr, sizeof(responseStr));
1035 free(responseStr);
1036}
1037
Mark Salyzynba58c202014-03-12 15:20:22 -07001038static void requestCdmaDeviceIdentity(int request __unused, void *data __unused,
1039 size_t datalen __unused, RIL_Token t)
The Android Open Source Project00f06fc2009-03-03 19:32:15 -08001040{
1041 int err;
1042 int response[4];
1043 char * responseStr[4];
1044 ATResponse *p_response = NULL;
1045 const char *cmd;
1046 const char *prefix;
1047 char *line, *p;
1048 int commas;
1049 int skip;
Jaime A Lopez-Sollanoe9645042012-08-29 07:27:27 -07001050 int count = 4;
The Android Open Source Project00f06fc2009-03-03 19:32:15 -08001051
Jaime A Lopez-Sollanoe9645042012-08-29 07:27:27 -07001052 // Fixed values. TODO: Query modem
1053 responseStr[0] = "----";
1054 responseStr[1] = "----";
1055 responseStr[2] = "77777777";
The Android Open Source Project00f06fc2009-03-03 19:32:15 -08001056
Jaime A Lopez-Sollanoe9645042012-08-29 07:27:27 -07001057 err = at_send_command_numeric("AT+CGSN", &p_response);
1058 if (err < 0 || p_response->success == 0) {
1059 RIL_onRequestComplete(t, RIL_E_GENERIC_FAILURE, NULL, 0);
1060 return;
The Android Open Source Project00f06fc2009-03-03 19:32:15 -08001061 } else {
Jaime A Lopez-Sollanoe9645042012-08-29 07:27:27 -07001062 responseStr[3] = p_response->p_intermediates->line;
The Android Open Source Project00f06fc2009-03-03 19:32:15 -08001063 }
1064
Jaime A Lopez-Sollanoe9645042012-08-29 07:27:27 -07001065 RIL_onRequestComplete(t, RIL_E_SUCCESS, responseStr, count*sizeof(char*));
1066 at_response_free(p_response);
The Android Open Source Project00f06fc2009-03-03 19:32:15 -08001067
Jaime A Lopez-Sollanoe9645042012-08-29 07:27:27 -07001068 return;
1069error:
Wink Saville4dcab4f2012-11-19 16:05:13 -08001070 RLOGE("requestCdmaDeviceIdentity must never return an error when radio is on");
Jaime A Lopez-Sollanoe9645042012-08-29 07:27:27 -07001071 at_response_free(p_response);
1072 RIL_onRequestComplete(t, RIL_E_GENERIC_FAILURE, NULL, 0);
1073}
1074
Mark Salyzynba58c202014-03-12 15:20:22 -07001075static void requestCdmaGetSubscriptionSource(int request __unused, void *data,
1076 size_t datalen __unused, RIL_Token t)
Jaime A Lopez-Sollanoe9645042012-08-29 07:27:27 -07001077{
1078 int err;
1079 int *ss = (int *)data;
1080 ATResponse *p_response = NULL;
1081 char *cmd = NULL;
1082 char *line = NULL;
1083 int response;
1084
1085 asprintf(&cmd, "AT+CCSS?");
1086 if (!cmd) goto error;
1087
1088 err = at_send_command_singleline(cmd, "+CCSS:", &p_response);
1089 if (err < 0 || !p_response->success)
1090 goto error;
The Android Open Source Project00f06fc2009-03-03 19:32:15 -08001091
1092 line = p_response->p_intermediates->line;
Jaime A Lopez-Sollanoe9645042012-08-29 07:27:27 -07001093 err = at_tok_start(&line);
1094 if (err < 0) goto error;
The Android Open Source Project00f06fc2009-03-03 19:32:15 -08001095
Jaime A Lopez-Sollanoe9645042012-08-29 07:27:27 -07001096 err = at_tok_nextint(&line, &response);
1097 free(cmd);
1098 cmd = NULL;
1099
1100 RIL_onRequestComplete(t, RIL_E_SUCCESS, &response, sizeof(response));
1101
1102 return;
1103error:
1104 free(cmd);
1105 RIL_onRequestComplete(t, RIL_E_GENERIC_FAILURE, NULL, 0);
1106}
1107
Mark Salyzynba58c202014-03-12 15:20:22 -07001108static void requestCdmaSetSubscriptionSource(int request __unused, void *data,
Jaime A Lopez-Sollanoe9645042012-08-29 07:27:27 -07001109 size_t datalen, RIL_Token t)
1110{
1111 int err;
1112 int *ss = (int *)data;
1113 ATResponse *p_response = NULL;
1114 char *cmd = NULL;
1115
1116 if (!ss || !datalen) {
Wink Saville4dcab4f2012-11-19 16:05:13 -08001117 RLOGE("RIL_REQUEST_CDMA_SET_SUBSCRIPTION without data!");
Jaime A Lopez-Sollanoe9645042012-08-29 07:27:27 -07001118 RIL_onRequestComplete(t, RIL_E_GENERIC_FAILURE, NULL, 0);
1119 return;
1120 }
1121 asprintf(&cmd, "AT+CCSS=%d", ss[0]);
1122 if (!cmd) goto error;
1123
1124 err = at_send_command(cmd, &p_response);
1125 if (err < 0 || !p_response->success)
1126 goto error;
1127 free(cmd);
1128 cmd = NULL;
1129
1130 RIL_onRequestComplete(t, RIL_E_SUCCESS, NULL, 0);
1131
1132 RIL_onUnsolicitedResponse(RIL_UNSOL_CDMA_SUBSCRIPTION_SOURCE_CHANGED, ss, sizeof(ss[0]));
1133
1134 return;
1135error:
1136 free(cmd);
1137 RIL_onRequestComplete(t, RIL_E_GENERIC_FAILURE, NULL, 0);
1138}
1139
Mark Salyzynba58c202014-03-12 15:20:22 -07001140static void requestCdmaSubscription(int request __unused, void *data __unused,
1141 size_t datalen __unused, RIL_Token t)
Jaime A Lopez-Sollanoe9645042012-08-29 07:27:27 -07001142{
1143 int err;
1144 int response[5];
1145 char * responseStr[5];
1146 ATResponse *p_response = NULL;
1147 const char *cmd;
1148 const char *prefix;
1149 char *line, *p;
1150 int commas;
1151 int skip;
1152 int count = 5;
1153
1154 // Fixed values. TODO: Query modem
1155 responseStr[0] = "8587777777"; // MDN
1156 responseStr[1] = "1"; // SID
1157 responseStr[2] = "1"; // NID
1158 responseStr[3] = "8587777777"; // MIN
1159 responseStr[4] = "1"; // PRL Version
1160 RIL_onRequestComplete(t, RIL_E_SUCCESS, responseStr, count*sizeof(char*));
1161
1162 return;
1163error:
Wink Saville4dcab4f2012-11-19 16:05:13 -08001164 RLOGE("requestRegistrationState must never return an error when radio is on");
Jaime A Lopez-Sollanoe9645042012-08-29 07:27:27 -07001165 RIL_onRequestComplete(t, RIL_E_GENERIC_FAILURE, NULL, 0);
1166}
1167
Mark Salyzynba58c202014-03-12 15:20:22 -07001168static void requestCdmaGetRoamingPreference(int request __unused, void *data __unused,
1169 size_t datalen __unused, RIL_Token t)
Jaime A Lopez-Sollanoe9645042012-08-29 07:27:27 -07001170{
1171 int roaming_pref = -1;
1172 ATResponse *p_response = NULL;
1173 char *line;
1174 int res;
1175
1176 res = at_send_command_singleline("AT+WRMP?", "+WRMP:", &p_response);
1177 if (res < 0 || !p_response->success) {
1178 goto error;
1179 }
1180 line = p_response->p_intermediates->line;
1181
1182 res = at_tok_start(&line);
1183 if (res < 0) goto error;
1184
1185 res = at_tok_nextint(&line, &roaming_pref);
1186 if (res < 0) goto error;
1187
1188 RIL_onRequestComplete(t, RIL_E_SUCCESS, &roaming_pref, sizeof(roaming_pref));
1189 return;
1190error:
1191 RIL_onRequestComplete(t, RIL_E_GENERIC_FAILURE, NULL, 0);
1192}
1193
Mark Salyzynba58c202014-03-12 15:20:22 -07001194static void requestCdmaSetRoamingPreference(int request __unused, void *data,
1195 size_t datalen __unused, RIL_Token t)
Jaime A Lopez-Sollanoe9645042012-08-29 07:27:27 -07001196{
1197 int *pref = (int *)data;
1198 ATResponse *p_response = NULL;
1199 char *line;
1200 int res;
1201 char *cmd = NULL;
1202
1203 asprintf(&cmd, "AT+WRMP=%d", *pref);
1204 if (cmd == NULL) goto error;
1205
1206 res = at_send_command(cmd, &p_response);
1207 if (res < 0 || !p_response->success)
1208 goto error;
1209
1210 RIL_onRequestComplete(t, RIL_E_SUCCESS, NULL, 0);
1211 free(cmd);
1212 return;
1213error:
1214 free(cmd);
1215 RIL_onRequestComplete(t, RIL_E_GENERIC_FAILURE, NULL, 0);
1216}
1217
1218static int parseRegistrationState(char *str, int *type, int *items, int **response)
1219{
1220 int err;
1221 char *line = str, *p;
1222 int *resp = NULL;
1223 int skip;
1224 int count = 3;
1225 int commas;
1226
Wink Saville4dcab4f2012-11-19 16:05:13 -08001227 RLOGD("parseRegistrationState. Parsing: %s",str);
The Android Open Source Project00f06fc2009-03-03 19:32:15 -08001228 err = at_tok_start(&line);
1229 if (err < 0) goto error;
1230
1231 /* Ok you have to be careful here
1232 * The solicited version of the CREG response is
1233 * +CREG: n, stat, [lac, cid]
1234 * and the unsolicited version is
1235 * +CREG: stat, [lac, cid]
1236 * The <n> parameter is basically "is unsolicited creg on?"
1237 * which it should always be
1238 *
1239 * Now we should normally get the solicited version here,
1240 * but the unsolicited version could have snuck in
1241 * so we have to handle both
1242 *
1243 * Also since the LAC and CID are only reported when registered,
1244 * we can have 1, 2, 3, or 4 arguments here
1245 *
1246 * finally, a +CGREG: answer may have a fifth value that corresponds
1247 * to the network type, as in;
1248 *
1249 * +CGREG: n, stat [,lac, cid [,networkType]]
1250 */
1251
1252 /* count number of commas */
1253 commas = 0;
1254 for (p = line ; *p != '\0' ;p++) {
1255 if (*p == ',') commas++;
1256 }
1257
Jaime A Lopez-Sollanoe9645042012-08-29 07:27:27 -07001258 resp = (int *)calloc(commas + 1, sizeof(int));
1259 if (!resp) goto error;
The Android Open Source Project00f06fc2009-03-03 19:32:15 -08001260 switch (commas) {
1261 case 0: /* +CREG: <stat> */
Jaime A Lopez-Sollanoe9645042012-08-29 07:27:27 -07001262 err = at_tok_nextint(&line, &resp[0]);
The Android Open Source Project00f06fc2009-03-03 19:32:15 -08001263 if (err < 0) goto error;
Jaime A Lopez-Sollanoe9645042012-08-29 07:27:27 -07001264 resp[1] = -1;
1265 resp[2] = -1;
The Android Open Source Project00f06fc2009-03-03 19:32:15 -08001266 break;
1267
1268 case 1: /* +CREG: <n>, <stat> */
1269 err = at_tok_nextint(&line, &skip);
1270 if (err < 0) goto error;
Jaime A Lopez-Sollanoe9645042012-08-29 07:27:27 -07001271 err = at_tok_nextint(&line, &resp[0]);
The Android Open Source Project00f06fc2009-03-03 19:32:15 -08001272 if (err < 0) goto error;
Jaime A Lopez-Sollanoe9645042012-08-29 07:27:27 -07001273 resp[1] = -1;
1274 resp[2] = -1;
The Android Open Source Project00f06fc2009-03-03 19:32:15 -08001275 if (err < 0) goto error;
1276 break;
1277
1278 case 2: /* +CREG: <stat>, <lac>, <cid> */
Jaime A Lopez-Sollanoe9645042012-08-29 07:27:27 -07001279 err = at_tok_nextint(&line, &resp[0]);
The Android Open Source Project00f06fc2009-03-03 19:32:15 -08001280 if (err < 0) goto error;
Jaime A Lopez-Sollanoe9645042012-08-29 07:27:27 -07001281 err = at_tok_nexthexint(&line, &resp[1]);
The Android Open Source Project00f06fc2009-03-03 19:32:15 -08001282 if (err < 0) goto error;
Jaime A Lopez-Sollanoe9645042012-08-29 07:27:27 -07001283 err = at_tok_nexthexint(&line, &resp[2]);
The Android Open Source Project00f06fc2009-03-03 19:32:15 -08001284 if (err < 0) goto error;
1285 break;
1286 case 3: /* +CREG: <n>, <stat>, <lac>, <cid> */
1287 err = at_tok_nextint(&line, &skip);
1288 if (err < 0) goto error;
Jaime A Lopez-Sollanoe9645042012-08-29 07:27:27 -07001289 err = at_tok_nextint(&line, &resp[0]);
The Android Open Source Project00f06fc2009-03-03 19:32:15 -08001290 if (err < 0) goto error;
Jaime A Lopez-Sollanoe9645042012-08-29 07:27:27 -07001291 err = at_tok_nexthexint(&line, &resp[1]);
The Android Open Source Project00f06fc2009-03-03 19:32:15 -08001292 if (err < 0) goto error;
Jaime A Lopez-Sollanoe9645042012-08-29 07:27:27 -07001293 err = at_tok_nexthexint(&line, &resp[2]);
The Android Open Source Project00f06fc2009-03-03 19:32:15 -08001294 if (err < 0) goto error;
1295 break;
1296 /* special case for CGREG, there is a fourth parameter
1297 * that is the network type (unknown/gprs/edge/umts)
1298 */
1299 case 4: /* +CGREG: <n>, <stat>, <lac>, <cid>, <networkType> */
1300 err = at_tok_nextint(&line, &skip);
1301 if (err < 0) goto error;
Jaime A Lopez-Sollanoe9645042012-08-29 07:27:27 -07001302 err = at_tok_nextint(&line, &resp[0]);
The Android Open Source Project00f06fc2009-03-03 19:32:15 -08001303 if (err < 0) goto error;
Jaime A Lopez-Sollanoe9645042012-08-29 07:27:27 -07001304 err = at_tok_nexthexint(&line, &resp[1]);
The Android Open Source Project00f06fc2009-03-03 19:32:15 -08001305 if (err < 0) goto error;
Jaime A Lopez-Sollanoe9645042012-08-29 07:27:27 -07001306 err = at_tok_nexthexint(&line, &resp[2]);
The Android Open Source Project00f06fc2009-03-03 19:32:15 -08001307 if (err < 0) goto error;
Jaime A Lopez-Sollanoe9645042012-08-29 07:27:27 -07001308 err = at_tok_nexthexint(&line, &resp[3]);
The Android Open Source Project00f06fc2009-03-03 19:32:15 -08001309 if (err < 0) goto error;
1310 count = 4;
1311 break;
1312 default:
1313 goto error;
1314 }
Wink Saville8a9e0212013-04-09 12:11:38 -07001315 s_lac = resp[1];
1316 s_cid = resp[2];
Jaime A Lopez-Sollanoe9645042012-08-29 07:27:27 -07001317 if (response)
1318 *response = resp;
1319 if (items)
1320 *items = commas + 1;
1321 if (type)
1322 *type = techFromModemType(TECH(sMdmInfo));
1323 return 0;
1324error:
1325 free(resp);
1326 return -1;
1327}
The Android Open Source Project00f06fc2009-03-03 19:32:15 -08001328
Jaime A Lopez-Sollanoe9645042012-08-29 07:27:27 -07001329#define REG_STATE_LEN 15
1330#define REG_DATA_STATE_LEN 6
Mark Salyzynba58c202014-03-12 15:20:22 -07001331static void requestRegistrationState(int request, void *data __unused,
1332 size_t datalen __unused, RIL_Token t)
Jaime A Lopez-Sollanoe9645042012-08-29 07:27:27 -07001333{
1334 int err;
1335 int *registration;
1336 char **responseStr = NULL;
1337 ATResponse *p_response = NULL;
1338 const char *cmd;
1339 const char *prefix;
1340 char *line;
1341 int i = 0, j, numElements = 0;
1342 int count = 3;
1343 int type, startfrom;
The Android Open Source Project00f06fc2009-03-03 19:32:15 -08001344
Wink Saville4dcab4f2012-11-19 16:05:13 -08001345 RLOGD("requestRegistrationState");
Jaime A Lopez-Sollanoe9645042012-08-29 07:27:27 -07001346 if (request == RIL_REQUEST_VOICE_REGISTRATION_STATE) {
1347 cmd = "AT+CREG?";
1348 prefix = "+CREG:";
1349 numElements = REG_STATE_LEN;
1350 } else if (request == RIL_REQUEST_DATA_REGISTRATION_STATE) {
1351 cmd = "AT+CGREG?";
1352 prefix = "+CGREG:";
1353 numElements = REG_DATA_STATE_LEN;
1354 } else {
1355 assert(0);
1356 goto error;
1357 }
The Android Open Source Project00f06fc2009-03-03 19:32:15 -08001358
Jaime A Lopez-Sollanoe9645042012-08-29 07:27:27 -07001359 err = at_send_command_singleline(cmd, prefix, &p_response);
1360
1361 if (err != 0) goto error;
1362
1363 line = p_response->p_intermediates->line;
1364
1365 if (parseRegistrationState(line, &type, &count, &registration)) goto error;
1366
1367 responseStr = malloc(numElements * sizeof(char *));
1368 if (!responseStr) goto error;
1369 memset(responseStr, 0, numElements * sizeof(char *));
1370 /**
1371 * The first '4' bytes for both registration states remain the same.
1372 * But if the request is 'DATA_REGISTRATION_STATE',
1373 * the 5th and 6th byte(s) are optional.
1374 */
1375 if (is3gpp2(type) == 1) {
Wink Saville4dcab4f2012-11-19 16:05:13 -08001376 RLOGD("registration state type: 3GPP2");
Jaime A Lopez-Sollanoe9645042012-08-29 07:27:27 -07001377 // TODO: Query modem
1378 startfrom = 3;
1379 if(request == RIL_REQUEST_VOICE_REGISTRATION_STATE) {
1380 asprintf(&responseStr[3], "8"); // EvDo revA
1381 asprintf(&responseStr[4], "1"); // BSID
1382 asprintf(&responseStr[5], "123"); // Latitude
1383 asprintf(&responseStr[6], "222"); // Longitude
1384 asprintf(&responseStr[7], "0"); // CSS Indicator
1385 asprintf(&responseStr[8], "4"); // SID
1386 asprintf(&responseStr[9], "65535"); // NID
1387 asprintf(&responseStr[10], "0"); // Roaming indicator
1388 asprintf(&responseStr[11], "1"); // System is in PRL
1389 asprintf(&responseStr[12], "0"); // Default Roaming indicator
1390 asprintf(&responseStr[13], "0"); // Reason for denial
1391 asprintf(&responseStr[14], "0"); // Primary Scrambling Code of Current cell
1392 } else if (request == RIL_REQUEST_DATA_REGISTRATION_STATE) {
1393 asprintf(&responseStr[3], "8"); // Available data radio technology
1394 }
1395 } else { // type == RADIO_TECH_3GPP
Wink Saville4dcab4f2012-11-19 16:05:13 -08001396 RLOGD("registration state type: 3GPP");
Jaime A Lopez-Sollanoe9645042012-08-29 07:27:27 -07001397 startfrom = 0;
1398 asprintf(&responseStr[1], "%x", registration[1]);
1399 asprintf(&responseStr[2], "%x", registration[2]);
1400 if (count > 3)
1401 asprintf(&responseStr[3], "%d", registration[3]);
1402 }
1403 asprintf(&responseStr[0], "%d", registration[0]);
1404
1405 /**
1406 * Optional bytes for DATA_REGISTRATION_STATE request
1407 * 4th byte : Registration denial code
1408 * 5th byte : The max. number of simultaneous Data Calls
1409 */
1410 if(request == RIL_REQUEST_DATA_REGISTRATION_STATE) {
1411 // asprintf(&responseStr[4], "3");
1412 // asprintf(&responseStr[5], "1");
1413 }
1414
1415 for (j = startfrom; j < numElements; j++) {
1416 if (!responseStr[i]) goto error;
1417 }
1418 free(registration);
1419 registration = NULL;
1420
1421 RIL_onRequestComplete(t, RIL_E_SUCCESS, responseStr, numElements*sizeof(responseStr));
1422 for (j = 0; j < numElements; j++ ) {
1423 free(responseStr[j]);
1424 responseStr[j] = NULL;
1425 }
1426 free(responseStr);
1427 responseStr = NULL;
The Android Open Source Project00f06fc2009-03-03 19:32:15 -08001428 at_response_free(p_response);
1429
1430 return;
1431error:
Jaime A Lopez-Sollanoe9645042012-08-29 07:27:27 -07001432 if (responseStr) {
1433 for (j = 0; j < numElements; j++) {
1434 free(responseStr[j]);
1435 responseStr[j] = NULL;
1436 }
1437 free(responseStr);
1438 responseStr = NULL;
1439 }
Wink Saville4dcab4f2012-11-19 16:05:13 -08001440 RLOGE("requestRegistrationState must never return an error when radio is on");
The Android Open Source Project00f06fc2009-03-03 19:32:15 -08001441 RIL_onRequestComplete(t, RIL_E_GENERIC_FAILURE, NULL, 0);
1442 at_response_free(p_response);
1443}
1444
Mark Salyzynba58c202014-03-12 15:20:22 -07001445static void requestOperator(void *data __unused, size_t datalen __unused, RIL_Token t)
The Android Open Source Project00f06fc2009-03-03 19:32:15 -08001446{
1447 int err;
1448 int i;
1449 int skip;
1450 ATLine *p_cur;
1451 char *response[3];
1452
1453 memset(response, 0, sizeof(response));
1454
1455 ATResponse *p_response = NULL;
1456
1457 err = at_send_command_multiline(
1458 "AT+COPS=3,0;+COPS?;+COPS=3,1;+COPS?;+COPS=3,2;+COPS?",
1459 "+COPS:", &p_response);
1460
1461 /* we expect 3 lines here:
1462 * +COPS: 0,0,"T - Mobile"
1463 * +COPS: 0,1,"TMO"
1464 * +COPS: 0,2,"310170"
1465 */
1466
1467 if (err != 0) goto error;
1468
1469 for (i = 0, p_cur = p_response->p_intermediates
1470 ; p_cur != NULL
1471 ; p_cur = p_cur->p_next, i++
1472 ) {
1473 char *line = p_cur->line;
1474
1475 err = at_tok_start(&line);
1476 if (err < 0) goto error;
1477
1478 err = at_tok_nextint(&line, &skip);
1479 if (err < 0) goto error;
1480
1481 // If we're unregistered, we may just get
1482 // a "+COPS: 0" response
1483 if (!at_tok_hasmore(&line)) {
1484 response[i] = NULL;
1485 continue;
1486 }
1487
1488 err = at_tok_nextint(&line, &skip);
1489 if (err < 0) goto error;
1490
1491 // a "+COPS: 0, n" response is also possible
1492 if (!at_tok_hasmore(&line)) {
1493 response[i] = NULL;
1494 continue;
1495 }
1496
1497 err = at_tok_nextstr(&line, &(response[i]));
1498 if (err < 0) goto error;
Wink Saville8a9e0212013-04-09 12:11:38 -07001499 // Simple assumption that mcc and mnc are 3 digits each
1500 if (strlen(response[i]) == 6) {
1501 if (sscanf(response[i], "%3d%3d", &s_mcc, &s_mnc) != 2) {
1502 RLOGE("requestOperator expected mccmnc to be 6 decimal digits");
1503 }
1504 }
The Android Open Source Project00f06fc2009-03-03 19:32:15 -08001505 }
1506
1507 if (i != 3) {
1508 /* expect 3 lines exactly */
1509 goto error;
1510 }
1511
1512 RIL_onRequestComplete(t, RIL_E_SUCCESS, response, sizeof(response));
1513 at_response_free(p_response);
1514
1515 return;
1516error:
Wink Saville4dcab4f2012-11-19 16:05:13 -08001517 RLOGE("requestOperator must not return error when radio is on");
The Android Open Source Project00f06fc2009-03-03 19:32:15 -08001518 RIL_onRequestComplete(t, RIL_E_GENERIC_FAILURE, NULL, 0);
1519 at_response_free(p_response);
1520}
1521
Jaime A Lopez-Sollanoe9645042012-08-29 07:27:27 -07001522static void requestCdmaSendSMS(void *data, size_t datalen, RIL_Token t)
1523{
1524 int err = 1; // Set to go to error:
1525 RIL_SMS_Response response;
1526 RIL_CDMA_SMS_Message* rcsm;
1527
Mark Salyzynba58c202014-03-12 15:20:22 -07001528 RLOGD("requestCdmaSendSMS datalen=%zu, sizeof(RIL_CDMA_SMS_Message)=%zu",
Jaime A Lopez-Sollanoe9645042012-08-29 07:27:27 -07001529 datalen, sizeof(RIL_CDMA_SMS_Message));
1530
1531 // verify data content to test marshalling/unmarshalling:
1532 rcsm = (RIL_CDMA_SMS_Message*)data;
Wink Saville4dcab4f2012-11-19 16:05:13 -08001533 RLOGD("TeleserviceID=%d, bIsServicePresent=%d, \
Jaime A Lopez-Sollanoe9645042012-08-29 07:27:27 -07001534 uServicecategory=%d, sAddress.digit_mode=%d, \
1535 sAddress.Number_mode=%d, sAddress.number_type=%d, ",
1536 rcsm->uTeleserviceID, rcsm->bIsServicePresent,
1537 rcsm->uServicecategory,rcsm->sAddress.digit_mode,
1538 rcsm->sAddress.number_mode,rcsm->sAddress.number_type);
1539
1540 if (err != 0) goto error;
1541
1542 // Cdma Send SMS implementation will go here:
1543 // But it is not implemented yet.
1544
1545 memset(&response, 0, sizeof(response));
Sukanya Rajkhowaa18b9d12013-09-10 12:30:13 -07001546 response.messageRef = 1;
Jaime A Lopez-Sollanoe9645042012-08-29 07:27:27 -07001547 RIL_onRequestComplete(t, RIL_E_SUCCESS, &response, sizeof(response));
1548 return;
1549
1550error:
1551 // Cdma Send SMS will always cause send retry error.
Sukanya Rajkhowaa18b9d12013-09-10 12:30:13 -07001552 response.messageRef = -1;
1553 RIL_onRequestComplete(t, RIL_E_SMS_SEND_FAIL_RETRY, &response, sizeof(response));
Jaime A Lopez-Sollanoe9645042012-08-29 07:27:27 -07001554}
1555
The Android Open Source Project00f06fc2009-03-03 19:32:15 -08001556static void requestSendSMS(void *data, size_t datalen, RIL_Token t)
1557{
1558 int err;
1559 const char *smsc;
1560 const char *pdu;
1561 int tpLayerLength;
1562 char *cmd1, *cmd2;
1563 RIL_SMS_Response response;
1564 ATResponse *p_response = NULL;
1565
Sukanya Rajkhowaa18b9d12013-09-10 12:30:13 -07001566 memset(&response, 0, sizeof(response));
Mark Salyzynba58c202014-03-12 15:20:22 -07001567 RLOGD("requestSendSMS datalen =%zu", datalen);
Sukanya Rajkhowaa18b9d12013-09-10 12:30:13 -07001568
1569 if (s_ims_gsm_fail != 0) goto error;
1570 if (s_ims_gsm_retry != 0) goto error2;
1571
The Android Open Source Project00f06fc2009-03-03 19:32:15 -08001572 smsc = ((const char **)data)[0];
1573 pdu = ((const char **)data)[1];
1574
1575 tpLayerLength = strlen(pdu)/2;
1576
1577 // "NULL for default SMSC"
1578 if (smsc == NULL) {
1579 smsc= "00";
1580 }
1581
1582 asprintf(&cmd1, "AT+CMGS=%d", tpLayerLength);
1583 asprintf(&cmd2, "%s%s", smsc, pdu);
1584
1585 err = at_send_command_sms(cmd1, cmd2, "+CMGS:", &p_response);
1586
1587 if (err != 0 || p_response->success == 0) goto error;
1588
The Android Open Source Project00f06fc2009-03-03 19:32:15 -08001589 /* FIXME fill in messageRef and ackPDU */
Sukanya Rajkhowaa18b9d12013-09-10 12:30:13 -07001590 response.messageRef = 1;
The Android Open Source Project00f06fc2009-03-03 19:32:15 -08001591 RIL_onRequestComplete(t, RIL_E_SUCCESS, &response, sizeof(response));
1592 at_response_free(p_response);
1593
1594 return;
1595error:
Sukanya Rajkhowaa18b9d12013-09-10 12:30:13 -07001596 response.messageRef = -2;
1597 RIL_onRequestComplete(t, RIL_E_GENERIC_FAILURE, &response, sizeof(response));
The Android Open Source Project00f06fc2009-03-03 19:32:15 -08001598 at_response_free(p_response);
Sukanya Rajkhowaa18b9d12013-09-10 12:30:13 -07001599 return;
1600error2:
1601 // send retry error.
1602 response.messageRef = -1;
1603 RIL_onRequestComplete(t, RIL_E_SMS_SEND_FAIL_RETRY, &response, sizeof(response));
1604 at_response_free(p_response);
1605 return;
1606 }
1607
1608static void requestImsSendSMS(void *data, size_t datalen, RIL_Token t)
1609{
1610 RIL_IMS_SMS_Message *p_args;
1611 RIL_SMS_Response response;
1612
1613 memset(&response, 0, sizeof(response));
1614
Mark Salyzynba58c202014-03-12 15:20:22 -07001615 RLOGD("requestImsSendSMS: datalen=%zu, "
Sukanya Rajkhowaa18b9d12013-09-10 12:30:13 -07001616 "registered=%d, service=%d, format=%d, ims_perm_fail=%d, "
1617 "ims_retry=%d, gsm_fail=%d, gsm_retry=%d",
1618 datalen, s_ims_registered, s_ims_services, s_ims_format,
1619 s_ims_cause_perm_failure, s_ims_cause_retry, s_ims_gsm_fail,
1620 s_ims_gsm_retry);
1621
1622 // figure out if this is gsm/cdma format
1623 // then route it to requestSendSMS vs requestCdmaSendSMS respectively
1624 p_args = (RIL_IMS_SMS_Message *)data;
1625
1626 if (0 != s_ims_cause_perm_failure ) goto error;
1627
1628 // want to fail over ims and this is first request over ims
1629 if (0 != s_ims_cause_retry && 0 == p_args->retry) goto error2;
1630
1631 if (RADIO_TECH_3GPP == p_args->tech) {
1632 return requestSendSMS(p_args->message.gsmMessage,
1633 datalen - sizeof(RIL_RadioTechnologyFamily),
1634 t);
1635 } else if (RADIO_TECH_3GPP2 == p_args->tech) {
1636 return requestCdmaSendSMS(p_args->message.cdmaMessage,
1637 datalen - sizeof(RIL_RadioTechnologyFamily),
1638 t);
1639 } else {
1640 RLOGE("requestImsSendSMS invalid format value =%d", p_args->tech);
1641 }
1642
1643error:
1644 response.messageRef = -2;
1645 RIL_onRequestComplete(t, RIL_E_GENERIC_FAILURE, &response, sizeof(response));
1646 return;
1647
1648error2:
1649 response.messageRef = -1;
1650 RIL_onRequestComplete(t, RIL_E_SMS_SEND_FAIL_RETRY, &response, sizeof(response));
The Android Open Source Project00f06fc2009-03-03 19:32:15 -08001651}
1652
Wink Savillef4c4d362009-04-02 01:37:03 -07001653static void requestSetupDataCall(void *data, size_t datalen, RIL_Token t)
The Android Open Source Project00f06fc2009-03-03 19:32:15 -08001654{
1655 const char *apn;
1656 char *cmd;
1657 int err;
1658 ATResponse *p_response = NULL;
The Android Open Source Project00f06fc2009-03-03 19:32:15 -08001659
Wink Savillef4c4d362009-04-02 01:37:03 -07001660 apn = ((const char **)data)[2];
The Android Open Source Project00f06fc2009-03-03 19:32:15 -08001661
1662#ifdef USE_TI_COMMANDS
1663 // Config for multislot class 10 (probably default anyway eh?)
1664 err = at_send_command("AT%CPRIM=\"GMM\",\"CONFIG MULTISLOT_CLASS=<10>\"",
1665 NULL);
1666
1667 err = at_send_command("AT%DATA=2,\"UART\",1,,\"SER\",\"UART\",0", NULL);
1668#endif /* USE_TI_COMMANDS */
1669
1670 int fd, qmistatus;
1671 size_t cur = 0;
1672 size_t len;
1673 ssize_t written, rlen;
1674 char status[32] = {0};
1675 int retry = 10;
Lorenzo Colitti4f81dcf2010-09-01 19:38:57 -07001676 const char *pdp_type;
The Android Open Source Project00f06fc2009-03-03 19:32:15 -08001677
Wink Saville4dcab4f2012-11-19 16:05:13 -08001678 RLOGD("requesting data connection to APN '%s'", apn);
The Android Open Source Project00f06fc2009-03-03 19:32:15 -08001679
1680 fd = open ("/dev/qmi", O_RDWR);
1681 if (fd >= 0) { /* the device doesn't exist on the emulator */
1682
Wink Saville4dcab4f2012-11-19 16:05:13 -08001683 RLOGD("opened the qmi device\n");
Lorenzo Colitti4f81dcf2010-09-01 19:38:57 -07001684 asprintf(&cmd, "up:%s", apn);
1685 len = strlen(cmd);
The Android Open Source Project00f06fc2009-03-03 19:32:15 -08001686
Lorenzo Colitti4f81dcf2010-09-01 19:38:57 -07001687 while (cur < len) {
1688 do {
1689 written = write (fd, cmd + cur, len - cur);
1690 } while (written < 0 && errno == EINTR);
The Android Open Source Project00f06fc2009-03-03 19:32:15 -08001691
Lorenzo Colitti4f81dcf2010-09-01 19:38:57 -07001692 if (written < 0) {
Wink Saville4dcab4f2012-11-19 16:05:13 -08001693 RLOGE("### ERROR writing to /dev/qmi");
The Android Open Source Project00f06fc2009-03-03 19:32:15 -08001694 close(fd);
1695 goto error;
1696 }
1697
1698 cur += written;
1699 }
1700
1701 // wait for interface to come online
1702
1703 do {
1704 sleep(1);
1705 do {
1706 rlen = read(fd, status, 31);
1707 } while (rlen < 0 && errno == EINTR);
1708
1709 if (rlen < 0) {
Wink Saville4dcab4f2012-11-19 16:05:13 -08001710 RLOGE("### ERROR reading from /dev/qmi");
The Android Open Source Project00f06fc2009-03-03 19:32:15 -08001711 close(fd);
1712 goto error;
1713 } else {
1714 status[rlen] = '\0';
Wink Saville4dcab4f2012-11-19 16:05:13 -08001715 RLOGD("### status: %s", status);
The Android Open Source Project00f06fc2009-03-03 19:32:15 -08001716 }
1717 } while (strncmp(status, "STATE=up", 8) && strcmp(status, "online") && --retry);
1718
1719 close(fd);
1720
1721 if (retry == 0) {
Wink Saville4dcab4f2012-11-19 16:05:13 -08001722 RLOGE("### Failed to get data connection up\n");
Lorenzo Colitti4f81dcf2010-09-01 19:38:57 -07001723 goto error;
1724 }
The Android Open Source Project00f06fc2009-03-03 19:32:15 -08001725
1726 qmistatus = system("netcfg rmnet0 dhcp");
1727
Wink Saville4dcab4f2012-11-19 16:05:13 -08001728 RLOGD("netcfg rmnet0 dhcp: status %d\n", qmistatus);
The Android Open Source Project00f06fc2009-03-03 19:32:15 -08001729
Lorenzo Colitti4f81dcf2010-09-01 19:38:57 -07001730 if (qmistatus < 0) goto error;
The Android Open Source Project00f06fc2009-03-03 19:32:15 -08001731
Lorenzo Colitti4f81dcf2010-09-01 19:38:57 -07001732 } else {
The Android Open Source Project00f06fc2009-03-03 19:32:15 -08001733
Lorenzo Colitti4f81dcf2010-09-01 19:38:57 -07001734 if (datalen > 6 * sizeof(char *)) {
1735 pdp_type = ((const char **)data)[6];
1736 } else {
1737 pdp_type = "IP";
1738 }
The Android Open Source Project00f06fc2009-03-03 19:32:15 -08001739
David 'Digit' Turneraf1298d2011-02-04 13:36:47 +01001740 asprintf(&cmd, "AT+CGDCONT=1,\"%s\",\"%s\",,0,0", pdp_type, apn);
Lorenzo Colitti4f81dcf2010-09-01 19:38:57 -07001741 //FIXME check for error here
1742 err = at_send_command(cmd, NULL);
1743 free(cmd);
The Android Open Source Project00f06fc2009-03-03 19:32:15 -08001744
Lorenzo Colitti4f81dcf2010-09-01 19:38:57 -07001745 // Set required QoS params to default
1746 err = at_send_command("AT+CGQREQ=1", NULL);
The Android Open Source Project00f06fc2009-03-03 19:32:15 -08001747
Lorenzo Colitti4f81dcf2010-09-01 19:38:57 -07001748 // Set minimum QoS params to default
1749 err = at_send_command("AT+CGQMIN=1", NULL);
The Android Open Source Project00f06fc2009-03-03 19:32:15 -08001750
Lorenzo Colitti4f81dcf2010-09-01 19:38:57 -07001751 // packet-domain event reporting
1752 err = at_send_command("AT+CGEREP=1,0", NULL);
The Android Open Source Project00f06fc2009-03-03 19:32:15 -08001753
Lorenzo Colitti4f81dcf2010-09-01 19:38:57 -07001754 // Hangup anything that's happening there now
1755 err = at_send_command("AT+CGACT=1,0", NULL);
The Android Open Source Project00f06fc2009-03-03 19:32:15 -08001756
Lorenzo Colitti4f81dcf2010-09-01 19:38:57 -07001757 // Start data on PDP context 1
1758 err = at_send_command("ATD*99***1#", &p_response);
1759
1760 if (err < 0 || p_response->success == 0) {
1761 goto error;
1762 }
The Android Open Source Project00f06fc2009-03-03 19:32:15 -08001763 }
1764
Wink Saville43808972011-01-13 17:39:51 -08001765 requestOrSendDataCallList(&t);
1766
The Android Open Source Project00f06fc2009-03-03 19:32:15 -08001767 at_response_free(p_response);
1768
1769 return;
1770error:
1771 RIL_onRequestComplete(t, RIL_E_GENERIC_FAILURE, NULL, 0);
1772 at_response_free(p_response);
1773
1774}
1775
Mark Salyzynba58c202014-03-12 15:20:22 -07001776static void requestSMSAcknowledge(void *data, size_t datalen __unused, RIL_Token t)
The Android Open Source Project00f06fc2009-03-03 19:32:15 -08001777{
1778 int ackSuccess;
1779 int err;
1780
1781 ackSuccess = ((int *)data)[0];
1782
1783 if (ackSuccess == 1) {
1784 err = at_send_command("AT+CNMA=1", NULL);
1785 } else if (ackSuccess == 0) {
1786 err = at_send_command("AT+CNMA=2", NULL);
1787 } else {
Wink Saville4dcab4f2012-11-19 16:05:13 -08001788 RLOGE("unsupported arg to RIL_REQUEST_SMS_ACKNOWLEDGE\n");
The Android Open Source Project00f06fc2009-03-03 19:32:15 -08001789 goto error;
1790 }
1791
1792 RIL_onRequestComplete(t, RIL_E_SUCCESS, NULL, 0);
1793error:
1794 RIL_onRequestComplete(t, RIL_E_GENERIC_FAILURE, NULL, 0);
1795
1796}
1797
Mark Salyzynba58c202014-03-12 15:20:22 -07001798static void requestSIM_IO(void *data, size_t datalen __unused, RIL_Token t)
The Android Open Source Project00f06fc2009-03-03 19:32:15 -08001799{
1800 ATResponse *p_response = NULL;
1801 RIL_SIM_IO_Response sr;
1802 int err;
1803 char *cmd = NULL;
Wink Saville2c1fb3a2011-03-19 13:42:45 -07001804 RIL_SIM_IO_v6 *p_args;
The Android Open Source Project00f06fc2009-03-03 19:32:15 -08001805 char *line;
1806
1807 memset(&sr, 0, sizeof(sr));
1808
Wink Saville2c1fb3a2011-03-19 13:42:45 -07001809 p_args = (RIL_SIM_IO_v6 *)data;
The Android Open Source Project00f06fc2009-03-03 19:32:15 -08001810
1811 /* FIXME handle pin2 */
1812
1813 if (p_args->data == NULL) {
1814 asprintf(&cmd, "AT+CRSM=%d,%d,%d,%d,%d",
1815 p_args->command, p_args->fileid,
1816 p_args->p1, p_args->p2, p_args->p3);
1817 } else {
1818 asprintf(&cmd, "AT+CRSM=%d,%d,%d,%d,%d,%s",
1819 p_args->command, p_args->fileid,
1820 p_args->p1, p_args->p2, p_args->p3, p_args->data);
1821 }
1822
1823 err = at_send_command_singleline(cmd, "+CRSM:", &p_response);
1824
1825 if (err < 0 || p_response->success == 0) {
1826 goto error;
1827 }
1828
1829 line = p_response->p_intermediates->line;
1830
1831 err = at_tok_start(&line);
1832 if (err < 0) goto error;
1833
1834 err = at_tok_nextint(&line, &(sr.sw1));
1835 if (err < 0) goto error;
1836
1837 err = at_tok_nextint(&line, &(sr.sw2));
1838 if (err < 0) goto error;
1839
1840 if (at_tok_hasmore(&line)) {
1841 err = at_tok_nextstr(&line, &(sr.simResponse));
1842 if (err < 0) goto error;
1843 }
1844
1845 RIL_onRequestComplete(t, RIL_E_SUCCESS, &sr, sizeof(sr));
1846 at_response_free(p_response);
1847 free(cmd);
1848
1849 return;
1850error:
1851 RIL_onRequestComplete(t, RIL_E_GENERIC_FAILURE, NULL, 0);
1852 at_response_free(p_response);
1853 free(cmd);
1854
1855}
1856
1857static void requestEnterSimPin(void* data, size_t datalen, RIL_Token t)
1858{
1859 ATResponse *p_response = NULL;
1860 int err;
1861 char* cmd = NULL;
1862 const char** strings = (const char**)data;;
1863
1864 if ( datalen == sizeof(char*) ) {
1865 asprintf(&cmd, "AT+CPIN=%s", strings[0]);
1866 } else if ( datalen == 2*sizeof(char*) ) {
1867 asprintf(&cmd, "AT+CPIN=%s,%s", strings[0], strings[1]);
1868 } else
1869 goto error;
1870
1871 err = at_send_command_singleline(cmd, "+CPIN:", &p_response);
1872 free(cmd);
1873
1874 if (err < 0 || p_response->success == 0) {
1875error:
1876 RIL_onRequestComplete(t, RIL_E_PASSWORD_INCORRECT, NULL, 0);
1877 } else {
1878 RIL_onRequestComplete(t, RIL_E_SUCCESS, NULL, 0);
1879 }
1880 at_response_free(p_response);
1881}
1882
1883
Mark Salyzynba58c202014-03-12 15:20:22 -07001884static void requestSendUSSD(void *data, size_t datalen __unused, RIL_Token t)
The Android Open Source Project00f06fc2009-03-03 19:32:15 -08001885{
1886 const char *ussdRequest;
1887
1888 ussdRequest = (char *)(data);
1889
1890
1891 RIL_onRequestComplete(t, RIL_E_REQUEST_NOT_SUPPORTED, NULL, 0);
1892
1893// @@@ TODO
1894
1895}
1896
Mark Salyzynba58c202014-03-12 15:20:22 -07001897static void requestExitEmergencyMode(void *data __unused, size_t datalen __unused, RIL_Token t)
Jaime A Lopez-Sollanoe9645042012-08-29 07:27:27 -07001898{
1899 int err;
1900 ATResponse *p_response = NULL;
1901
1902 err = at_send_command("AT+WSOS=0", &p_response);
1903
1904 if (err < 0 || p_response->success == 0) {
1905 RIL_onRequestComplete(t, RIL_E_GENERIC_FAILURE, NULL, 0);
1906 return;
1907 }
1908
1909 RIL_onRequestComplete(t, RIL_E_SUCCESS, NULL, 0);
1910}
1911
1912// TODO: Use all radio types
1913static int techFromModemType(int mdmtype)
1914{
1915 int ret = -1;
1916 switch (1 << mdmtype) {
1917 case MDM_CDMA:
1918 ret = RADIO_TECH_1xRTT;
1919 break;
1920 case MDM_EVDO:
1921 ret = RADIO_TECH_EVDO_A;
1922 break;
1923 case MDM_GSM:
1924 ret = RADIO_TECH_GPRS;
1925 break;
1926 case MDM_WCDMA:
1927 ret = RADIO_TECH_HSPA;
1928 break;
1929 case MDM_LTE:
1930 ret = RADIO_TECH_LTE;
1931 break;
1932 }
1933 return ret;
1934}
The Android Open Source Project00f06fc2009-03-03 19:32:15 -08001935
Mark Salyzynba58c202014-03-12 15:20:22 -07001936static void requestGetCellInfoList(void *data __unused, size_t datalen __unused, RIL_Token t)
Wink Saville8a9e0212013-04-09 12:11:38 -07001937{
1938 uint64_t curTime = ril_nano_time();
1939 RIL_CellInfo ci[1] =
1940 {
1941 { // ci[0]
1942 1, // cellInfoType
1943 1, // registered
Sanket Padawef0c8ca72016-06-30 15:01:08 -07001944 RIL_TIMESTAMP_TYPE_MODEM,
Wink Saville8a9e0212013-04-09 12:11:38 -07001945 curTime - 1000, // Fake some time in the past
1946 { // union CellInfo
1947 { // RIL_CellInfoGsm gsm
1948 { // gsm.cellIdneityGsm
1949 s_mcc, // mcc
1950 s_mnc, // mnc
1951 s_lac, // lac
1952 s_cid, // cid
Wink Saville8a9e0212013-04-09 12:11:38 -07001953 },
1954 { // gsm.signalStrengthGsm
1955 10, // signalStrength
1956 0 // bitErrorRate
1957 }
1958 }
1959 }
1960 }
1961 };
1962
1963 RIL_onRequestComplete(t, RIL_E_SUCCESS, ci, sizeof(ci));
1964}
1965
1966
Sanket Padawef0c8ca72016-06-30 15:01:08 -07001967static void requestSetCellInfoListRate(void *data, size_t datalen __unused, RIL_Token t)
Wink Saville8a9e0212013-04-09 12:11:38 -07001968{
1969 // For now we'll save the rate but no RIL_UNSOL_CELL_INFO_LIST messages
1970 // will be sent.
1971 assert (datalen == sizeof(int));
1972 s_cell_info_rate_ms = ((int *)data)[0];
1973
1974 RIL_onRequestComplete(t, RIL_E_SUCCESS, NULL, 0);
1975}
1976
Etan Cohend3652192014-06-20 08:28:44 -07001977static void requestGetHardwareConfig(void *data, size_t datalen, RIL_Token t)
1978{
1979 // TODO - hook this up with real query/info from radio.
1980
1981 RIL_HardwareConfig hwCfg;
1982
1983 RIL_UNUSED_PARM(data);
1984 RIL_UNUSED_PARM(datalen);
1985
1986 hwCfg.type = -1;
1987
1988 RIL_onRequestComplete(t, RIL_E_SUCCESS, &hwCfg, sizeof(hwCfg));
1989}
1990
1991
The Android Open Source Project00f06fc2009-03-03 19:32:15 -08001992/*** Callback methods from the RIL library to us ***/
1993
1994/**
1995 * Call from RIL to us to make a RIL_REQUEST
1996 *
1997 * Must be completed with a call to RIL_onRequestComplete()
1998 *
1999 * RIL_onRequestComplete() may be called from any thread, before or after
2000 * this function returns.
2001 *
2002 * Will always be called from the same thread, so returning here implies
2003 * that the radio is ready to process another command (whether or not
2004 * the previous command has completed).
2005 */
2006static void
2007onRequest (int request, void *data, size_t datalen, RIL_Token t)
2008{
2009 ATResponse *p_response;
2010 int err;
2011
Wink Saville4dcab4f2012-11-19 16:05:13 -08002012 RLOGD("onRequest: %s", requestToString(request));
The Android Open Source Project00f06fc2009-03-03 19:32:15 -08002013
2014 /* Ignore all requests except RIL_REQUEST_GET_SIM_STATUS
2015 * when RADIO_STATE_UNAVAILABLE.
2016 */
2017 if (sState == RADIO_STATE_UNAVAILABLE
2018 && request != RIL_REQUEST_GET_SIM_STATUS
2019 ) {
2020 RIL_onRequestComplete(t, RIL_E_RADIO_NOT_AVAILABLE, NULL, 0);
2021 return;
2022 }
2023
2024 /* Ignore all non-power requests when RADIO_STATE_OFF
2025 * (except RIL_REQUEST_GET_SIM_STATUS)
2026 */
2027 if (sState == RADIO_STATE_OFF
2028 && !(request == RIL_REQUEST_RADIO_POWER
2029 || request == RIL_REQUEST_GET_SIM_STATUS)
2030 ) {
2031 RIL_onRequestComplete(t, RIL_E_RADIO_NOT_AVAILABLE, NULL, 0);
2032 return;
2033 }
2034
2035 switch (request) {
2036 case RIL_REQUEST_GET_SIM_STATUS: {
Wink Saville2c1fb3a2011-03-19 13:42:45 -07002037 RIL_CardStatus_v6 *p_card_status;
Wink Savillef6aa7c12009-04-30 14:20:52 -07002038 char *p_buffer;
2039 int buffer_size;
The Android Open Source Project00f06fc2009-03-03 19:32:15 -08002040
Wink Savillef6aa7c12009-04-30 14:20:52 -07002041 int result = getCardStatus(&p_card_status);
2042 if (result == RIL_E_SUCCESS) {
2043 p_buffer = (char *)p_card_status;
2044 buffer_size = sizeof(*p_card_status);
2045 } else {
2046 p_buffer = NULL;
2047 buffer_size = 0;
2048 }
2049 RIL_onRequestComplete(t, result, p_buffer, buffer_size);
2050 freeCardStatus(p_card_status);
The Android Open Source Project00f06fc2009-03-03 19:32:15 -08002051 break;
2052 }
2053 case RIL_REQUEST_GET_CURRENT_CALLS:
2054 requestGetCurrentCalls(data, datalen, t);
2055 break;
2056 case RIL_REQUEST_DIAL:
2057 requestDial(data, datalen, t);
2058 break;
2059 case RIL_REQUEST_HANGUP:
2060 requestHangup(data, datalen, t);
2061 break;
2062 case RIL_REQUEST_HANGUP_WAITING_OR_BACKGROUND:
2063 // 3GPP 22.030 6.5.5
2064 // "Releases all held calls or sets User Determined User Busy
2065 // (UDUB) for a waiting call."
2066 at_send_command("AT+CHLD=0", NULL);
2067
2068 /* success or failure is ignored by the upper layer here.
2069 it will call GET_CURRENT_CALLS and determine success that way */
2070 RIL_onRequestComplete(t, RIL_E_SUCCESS, NULL, 0);
2071 break;
2072 case RIL_REQUEST_HANGUP_FOREGROUND_RESUME_BACKGROUND:
2073 // 3GPP 22.030 6.5.5
2074 // "Releases all active calls (if any exist) and accepts
2075 // the other (held or waiting) call."
2076 at_send_command("AT+CHLD=1", NULL);
2077
2078 /* success or failure is ignored by the upper layer here.
2079 it will call GET_CURRENT_CALLS and determine success that way */
2080 RIL_onRequestComplete(t, RIL_E_SUCCESS, NULL, 0);
2081 break;
2082 case RIL_REQUEST_SWITCH_WAITING_OR_HOLDING_AND_ACTIVE:
2083 // 3GPP 22.030 6.5.5
2084 // "Places all active calls (if any exist) on hold and accepts
2085 // the other (held or waiting) call."
2086 at_send_command("AT+CHLD=2", NULL);
2087
2088#ifdef WORKAROUND_ERRONEOUS_ANSWER
2089 s_expectAnswer = 1;
2090#endif /* WORKAROUND_ERRONEOUS_ANSWER */
2091
2092 /* success or failure is ignored by the upper layer here.
2093 it will call GET_CURRENT_CALLS and determine success that way */
2094 RIL_onRequestComplete(t, RIL_E_SUCCESS, NULL, 0);
2095 break;
2096 case RIL_REQUEST_ANSWER:
2097 at_send_command("ATA", NULL);
2098
2099#ifdef WORKAROUND_ERRONEOUS_ANSWER
2100 s_expectAnswer = 1;
2101#endif /* WORKAROUND_ERRONEOUS_ANSWER */
2102
2103 /* success or failure is ignored by the upper layer here.
2104 it will call GET_CURRENT_CALLS and determine success that way */
2105 RIL_onRequestComplete(t, RIL_E_SUCCESS, NULL, 0);
2106 break;
2107 case RIL_REQUEST_CONFERENCE:
2108 // 3GPP 22.030 6.5.5
2109 // "Adds a held call to the conversation"
2110 at_send_command("AT+CHLD=3", NULL);
2111
2112 /* success or failure is ignored by the upper layer here.
2113 it will call GET_CURRENT_CALLS and determine success that way */
2114 RIL_onRequestComplete(t, RIL_E_SUCCESS, NULL, 0);
2115 break;
2116 case RIL_REQUEST_UDUB:
2117 /* user determined user busy */
2118 /* sometimes used: ATH */
2119 at_send_command("ATH", NULL);
2120
2121 /* success or failure is ignored by the upper layer here.
2122 it will call GET_CURRENT_CALLS and determine success that way */
2123 RIL_onRequestComplete(t, RIL_E_SUCCESS, NULL, 0);
2124 break;
2125
2126 case RIL_REQUEST_SEPARATE_CONNECTION:
2127 {
2128 char cmd[12];
2129 int party = ((int*)data)[0];
2130
2131 // Make sure that party is in a valid range.
2132 // (Note: The Telephony middle layer imposes a range of 1 to 7.
2133 // It's sufficient for us to just make sure it's single digit.)
2134 if (party > 0 && party < 10) {
2135 sprintf(cmd, "AT+CHLD=2%d", party);
2136 at_send_command(cmd, NULL);
2137 RIL_onRequestComplete(t, RIL_E_SUCCESS, NULL, 0);
2138 } else {
2139 RIL_onRequestComplete(t, RIL_E_GENERIC_FAILURE, NULL, 0);
2140 }
2141 }
2142 break;
2143
2144 case RIL_REQUEST_SIGNAL_STRENGTH:
2145 requestSignalStrength(data, datalen, t);
2146 break;
Wink Saville2c1fb3a2011-03-19 13:42:45 -07002147 case RIL_REQUEST_VOICE_REGISTRATION_STATE:
2148 case RIL_REQUEST_DATA_REGISTRATION_STATE:
The Android Open Source Project00f06fc2009-03-03 19:32:15 -08002149 requestRegistrationState(request, data, datalen, t);
2150 break;
2151 case RIL_REQUEST_OPERATOR:
2152 requestOperator(data, datalen, t);
2153 break;
2154 case RIL_REQUEST_RADIO_POWER:
2155 requestRadioPower(data, datalen, t);
2156 break;
2157 case RIL_REQUEST_DTMF: {
2158 char c = ((char *)data)[0];
2159 char *cmd;
2160 asprintf(&cmd, "AT+VTS=%c", (int)c);
2161 at_send_command(cmd, NULL);
2162 free(cmd);
2163 RIL_onRequestComplete(t, RIL_E_SUCCESS, NULL, 0);
2164 break;
2165 }
2166 case RIL_REQUEST_SEND_SMS:
Chaitanya Saggurthi33bbe432013-09-24 16:16:21 +05302167 case RIL_REQUEST_SEND_SMS_EXPECT_MORE:
The Android Open Source Project00f06fc2009-03-03 19:32:15 -08002168 requestSendSMS(data, datalen, t);
2169 break;
Jaime A Lopez-Sollanoe9645042012-08-29 07:27:27 -07002170 case RIL_REQUEST_CDMA_SEND_SMS:
2171 requestCdmaSendSMS(data, datalen, t);
2172 break;
Sukanya Rajkhowaa18b9d12013-09-10 12:30:13 -07002173 case RIL_REQUEST_IMS_SEND_SMS:
2174 requestImsSendSMS(data, datalen, t);
2175 break;
Wink Savillef4c4d362009-04-02 01:37:03 -07002176 case RIL_REQUEST_SETUP_DATA_CALL:
2177 requestSetupDataCall(data, datalen, t);
The Android Open Source Project00f06fc2009-03-03 19:32:15 -08002178 break;
2179 case RIL_REQUEST_SMS_ACKNOWLEDGE:
2180 requestSMSAcknowledge(data, datalen, t);
2181 break;
2182
2183 case RIL_REQUEST_GET_IMSI:
2184 p_response = NULL;
2185 err = at_send_command_numeric("AT+CIMI", &p_response);
2186
2187 if (err < 0 || p_response->success == 0) {
2188 RIL_onRequestComplete(t, RIL_E_GENERIC_FAILURE, NULL, 0);
2189 } else {
2190 RIL_onRequestComplete(t, RIL_E_SUCCESS,
2191 p_response->p_intermediates->line, sizeof(char *));
2192 }
2193 at_response_free(p_response);
2194 break;
2195
2196 case RIL_REQUEST_GET_IMEI:
2197 p_response = NULL;
2198 err = at_send_command_numeric("AT+CGSN", &p_response);
2199
2200 if (err < 0 || p_response->success == 0) {
2201 RIL_onRequestComplete(t, RIL_E_GENERIC_FAILURE, NULL, 0);
2202 } else {
2203 RIL_onRequestComplete(t, RIL_E_SUCCESS,
2204 p_response->p_intermediates->line, sizeof(char *));
2205 }
2206 at_response_free(p_response);
2207 break;
2208
2209 case RIL_REQUEST_SIM_IO:
2210 requestSIM_IO(data,datalen,t);
2211 break;
2212
2213 case RIL_REQUEST_SEND_USSD:
2214 requestSendUSSD(data, datalen, t);
2215 break;
2216
2217 case RIL_REQUEST_CANCEL_USSD:
2218 p_response = NULL;
2219 err = at_send_command_numeric("AT+CUSD=2", &p_response);
2220
2221 if (err < 0 || p_response->success == 0) {
2222 RIL_onRequestComplete(t, RIL_E_GENERIC_FAILURE, NULL, 0);
2223 } else {
2224 RIL_onRequestComplete(t, RIL_E_SUCCESS,
2225 p_response->p_intermediates->line, sizeof(char *));
2226 }
2227 at_response_free(p_response);
2228 break;
2229
2230 case RIL_REQUEST_SET_NETWORK_SELECTION_AUTOMATIC:
2231 at_send_command("AT+COPS=0", NULL);
2232 break;
2233
Wink Savillef4c4d362009-04-02 01:37:03 -07002234 case RIL_REQUEST_DATA_CALL_LIST:
2235 requestDataCallList(data, datalen, t);
The Android Open Source Project00f06fc2009-03-03 19:32:15 -08002236 break;
2237
2238 case RIL_REQUEST_QUERY_NETWORK_SELECTION_MODE:
2239 requestQueryNetworkSelectionMode(data, datalen, t);
2240 break;
2241
2242 case RIL_REQUEST_OEM_HOOK_RAW:
2243 // echo back data
2244 RIL_onRequestComplete(t, RIL_E_SUCCESS, data, datalen);
2245 break;
2246
2247
2248 case RIL_REQUEST_OEM_HOOK_STRINGS: {
2249 int i;
2250 const char ** cur;
2251
Wink Saville4dcab4f2012-11-19 16:05:13 -08002252 RLOGD("got OEM_HOOK_STRINGS: 0x%8p %lu", data, (long)datalen);
The Android Open Source Project00f06fc2009-03-03 19:32:15 -08002253
2254
2255 for (i = (datalen / sizeof (char *)), cur = (const char **)data ;
2256 i > 0 ; cur++, i --) {
Wink Saville4dcab4f2012-11-19 16:05:13 -08002257 RLOGD("> '%s'", *cur);
The Android Open Source Project00f06fc2009-03-03 19:32:15 -08002258 }
2259
2260 // echo back strings
2261 RIL_onRequestComplete(t, RIL_E_SUCCESS, data, datalen);
2262 break;
2263 }
2264
2265 case RIL_REQUEST_WRITE_SMS_TO_SIM:
2266 requestWriteSmsToSim(data, datalen, t);
2267 break;
2268
2269 case RIL_REQUEST_DELETE_SMS_ON_SIM: {
2270 char * cmd;
2271 p_response = NULL;
2272 asprintf(&cmd, "AT+CMGD=%d", ((int *)data)[0]);
2273 err = at_send_command(cmd, &p_response);
2274 free(cmd);
2275 if (err < 0 || p_response->success == 0) {
2276 RIL_onRequestComplete(t, RIL_E_GENERIC_FAILURE, NULL, 0);
2277 } else {
2278 RIL_onRequestComplete(t, RIL_E_SUCCESS, NULL, 0);
2279 }
2280 at_response_free(p_response);
2281 break;
2282 }
2283
2284 case RIL_REQUEST_ENTER_SIM_PIN:
2285 case RIL_REQUEST_ENTER_SIM_PUK:
2286 case RIL_REQUEST_ENTER_SIM_PIN2:
2287 case RIL_REQUEST_ENTER_SIM_PUK2:
2288 case RIL_REQUEST_CHANGE_SIM_PIN:
2289 case RIL_REQUEST_CHANGE_SIM_PIN2:
2290 requestEnterSimPin(data, datalen, t);
2291 break;
2292
Sukanya Rajkhowaa18b9d12013-09-10 12:30:13 -07002293 case RIL_REQUEST_IMS_REGISTRATION_STATE: {
2294 int reply[2];
2295 //0==unregistered, 1==registered
2296 reply[0] = s_ims_registered;
2297
2298 //to be used when changed to include service supporated info
2299 //reply[1] = s_ims_services;
2300
2301 // FORMAT_3GPP(1) vs FORMAT_3GPP2(2);
2302 reply[1] = s_ims_format;
2303
2304 RLOGD("IMS_REGISTRATION=%d, format=%d ",
2305 reply[0], reply[1]);
2306 if (reply[1] != -1) {
2307 RIL_onRequestComplete(t, RIL_E_SUCCESS, reply, sizeof(reply));
2308 } else {
2309 RIL_onRequestComplete(t, RIL_E_GENERIC_FAILURE, NULL, 0);
2310 }
2311 break;
2312 }
2313
Jaime A Lopez-Sollanoe9645042012-08-29 07:27:27 -07002314 case RIL_REQUEST_VOICE_RADIO_TECH:
2315 {
2316 int tech = techFromModemType(TECH(sMdmInfo));
2317 if (tech < 0 )
2318 RIL_onRequestComplete(t, RIL_E_GENERIC_FAILURE, NULL, 0);
2319 else
2320 RIL_onRequestComplete(t, RIL_E_SUCCESS, &tech, sizeof(tech));
2321 }
2322 break;
2323 case RIL_REQUEST_SET_PREFERRED_NETWORK_TYPE:
2324 requestSetPreferredNetworkType(request, data, datalen, t);
2325 break;
2326
2327 case RIL_REQUEST_GET_PREFERRED_NETWORK_TYPE:
2328 requestGetPreferredNetworkType(request, data, datalen, t);
2329 break;
2330
Jun Tian58027012013-07-30 11:07:22 +08002331 case RIL_REQUEST_GET_CELL_INFO_LIST:
2332 requestGetCellInfoList(data, datalen, t);
2333 break;
2334
2335 case RIL_REQUEST_SET_UNSOL_CELL_INFO_LIST_RATE:
2336 requestSetCellInfoListRate(data, datalen, t);
2337 break;
2338
Etan Cohend3652192014-06-20 08:28:44 -07002339 case RIL_REQUEST_GET_HARDWARE_CONFIG:
2340 requestGetHardwareConfig(data, datalen, t);
2341 break;
2342
Naveen Kallaa65a16a2014-07-31 16:48:31 -07002343 case RIL_REQUEST_SHUTDOWN:
2344 requestShutdown(t);
2345 break;
2346
Jaime A Lopez-Sollanoe9645042012-08-29 07:27:27 -07002347 /* CDMA Specific Requests */
2348 case RIL_REQUEST_BASEBAND_VERSION:
2349 if (TECH_BIT(sMdmInfo) == MDM_CDMA) {
2350 requestCdmaBaseBandVersion(request, data, datalen, t);
2351 break;
2352 } // Fall-through if tech is not cdma
2353
2354 case RIL_REQUEST_DEVICE_IDENTITY:
2355 if (TECH_BIT(sMdmInfo) == MDM_CDMA) {
2356 requestCdmaDeviceIdentity(request, data, datalen, t);
2357 break;
2358 } // Fall-through if tech is not cdma
2359
2360 case RIL_REQUEST_CDMA_SUBSCRIPTION:
2361 if (TECH_BIT(sMdmInfo) == MDM_CDMA) {
2362 requestCdmaSubscription(request, data, datalen, t);
2363 break;
2364 } // Fall-through if tech is not cdma
2365
2366 case RIL_REQUEST_CDMA_SET_SUBSCRIPTION_SOURCE:
2367 if (TECH_BIT(sMdmInfo) == MDM_CDMA) {
2368 requestCdmaSetSubscriptionSource(request, data, datalen, t);
2369 break;
2370 } // Fall-through if tech is not cdma
2371
2372 case RIL_REQUEST_CDMA_GET_SUBSCRIPTION_SOURCE:
2373 if (TECH_BIT(sMdmInfo) == MDM_CDMA) {
2374 requestCdmaGetSubscriptionSource(request, data, datalen, t);
2375 break;
2376 } // Fall-through if tech is not cdma
2377
2378 case RIL_REQUEST_CDMA_QUERY_ROAMING_PREFERENCE:
2379 if (TECH_BIT(sMdmInfo) == MDM_CDMA) {
2380 requestCdmaGetRoamingPreference(request, data, datalen, t);
2381 break;
2382 } // Fall-through if tech is not cdma
2383
2384 case RIL_REQUEST_CDMA_SET_ROAMING_PREFERENCE:
2385 if (TECH_BIT(sMdmInfo) == MDM_CDMA) {
2386 requestCdmaSetRoamingPreference(request, data, datalen, t);
2387 break;
2388 } // Fall-through if tech is not cdma
2389
2390 case RIL_REQUEST_EXIT_EMERGENCY_CALLBACK_MODE:
2391 if (TECH_BIT(sMdmInfo) == MDM_CDMA) {
2392 requestExitEmergencyMode(data, datalen, t);
2393 break;
2394 } // Fall-through if tech is not cdma
2395
The Android Open Source Project00f06fc2009-03-03 19:32:15 -08002396 default:
Wink Saville4dcab4f2012-11-19 16:05:13 -08002397 RLOGD("Request not supported. Tech: %d",TECH(sMdmInfo));
The Android Open Source Project00f06fc2009-03-03 19:32:15 -08002398 RIL_onRequestComplete(t, RIL_E_REQUEST_NOT_SUPPORTED, NULL, 0);
2399 break;
2400 }
2401}
2402
2403/**
2404 * Synchronous call from the RIL to us to return current radio state.
2405 * RADIO_STATE_UNAVAILABLE should be the initial state.
2406 */
2407static RIL_RadioState
2408currentState()
2409{
2410 return sState;
2411}
2412/**
2413 * Call from RIL to us to find out whether a specific request code
2414 * is supported by this implementation.
2415 *
2416 * Return 1 for "supported" and 0 for "unsupported"
2417 */
2418
2419static int
Mark Salyzynba58c202014-03-12 15:20:22 -07002420onSupports (int requestCode __unused)
The Android Open Source Project00f06fc2009-03-03 19:32:15 -08002421{
2422 //@@@ todo
2423
2424 return 1;
2425}
2426
Mark Salyzynba58c202014-03-12 15:20:22 -07002427static void onCancel (RIL_Token t __unused)
The Android Open Source Project00f06fc2009-03-03 19:32:15 -08002428{
2429 //@@@todo
2430
2431}
2432
2433static const char * getVersion(void)
2434{
2435 return "android reference-ril 1.0";
2436}
2437
2438static void
Jaime A Lopez-Sollanoe9645042012-08-29 07:27:27 -07002439setRadioTechnology(ModemInfo *mdm, int newtech)
2440{
Wink Saville4dcab4f2012-11-19 16:05:13 -08002441 RLOGD("setRadioTechnology(%d)", newtech);
Jaime A Lopez-Sollanoe9645042012-08-29 07:27:27 -07002442
2443 int oldtech = TECH(mdm);
2444
2445 if (newtech != oldtech) {
Wink Saville4dcab4f2012-11-19 16:05:13 -08002446 RLOGD("Tech change (%d => %d)", oldtech, newtech);
Jaime A Lopez-Sollanoe9645042012-08-29 07:27:27 -07002447 TECH(mdm) = newtech;
2448 if (techFromModemType(newtech) != techFromModemType(oldtech)) {
2449 int tech = techFromModemType(TECH(sMdmInfo));
2450 if (tech > 0 ) {
2451 RIL_onUnsolicitedResponse(RIL_UNSOL_VOICE_RADIO_TECH_CHANGED,
2452 &tech, sizeof(tech));
2453 }
2454 }
2455 }
2456}
2457
2458static void
The Android Open Source Project00f06fc2009-03-03 19:32:15 -08002459setRadioState(RIL_RadioState newState)
2460{
Wink Saville4dcab4f2012-11-19 16:05:13 -08002461 RLOGD("setRadioState(%d)", newState);
The Android Open Source Project00f06fc2009-03-03 19:32:15 -08002462 RIL_RadioState oldState;
2463
2464 pthread_mutex_lock(&s_state_mutex);
2465
2466 oldState = sState;
2467
2468 if (s_closed > 0) {
2469 // If we're closed, the only reasonable state is
2470 // RADIO_STATE_UNAVAILABLE
2471 // This is here because things on the main thread
2472 // may attempt to change the radio state after the closed
2473 // event happened in another thread
2474 newState = RADIO_STATE_UNAVAILABLE;
2475 }
2476
2477 if (sState != newState || s_closed > 0) {
2478 sState = newState;
2479
2480 pthread_cond_broadcast (&s_state_cond);
2481 }
2482
2483 pthread_mutex_unlock(&s_state_mutex);
2484
2485
2486 /* do these outside of the mutex */
2487 if (sState != oldState) {
2488 RIL_onUnsolicitedResponse (RIL_UNSOL_RESPONSE_RADIO_STATE_CHANGED,
2489 NULL, 0);
Alex Yakavenka81d14852013-12-04 13:54:37 -08002490 // Sim state can change as result of radio state change
2491 RIL_onUnsolicitedResponse (RIL_UNSOL_RESPONSE_SIM_STATUS_CHANGED,
2492 NULL, 0);
The Android Open Source Project00f06fc2009-03-03 19:32:15 -08002493
2494 /* FIXME onSimReady() and onRadioPowerOn() cannot be called
2495 * from the AT reader thread
2496 * Currently, this doesn't happen, but if that changes then these
2497 * will need to be dispatched on the request thread
2498 */
Jaime A Lopez-Sollanoe9645042012-08-29 07:27:27 -07002499 if (sState == RADIO_STATE_ON) {
The Android Open Source Project00f06fc2009-03-03 19:32:15 -08002500 onRadioPowerOn();
2501 }
2502 }
2503}
2504
Jaime A Lopez-Sollanoe9645042012-08-29 07:27:27 -07002505/** Returns RUIM_NOT_READY on error */
2506static SIM_Status
2507getRUIMStatus()
2508{
2509 ATResponse *p_response = NULL;
2510 int err;
2511 int ret;
2512 char *cpinLine;
2513 char *cpinResult;
2514
2515 if (sState == RADIO_STATE_OFF || sState == RADIO_STATE_UNAVAILABLE) {
2516 ret = SIM_NOT_READY;
2517 goto done;
2518 }
2519
2520 err = at_send_command_singleline("AT+CPIN?", "+CPIN:", &p_response);
2521
2522 if (err != 0) {
2523 ret = SIM_NOT_READY;
2524 goto done;
2525 }
2526
2527 switch (at_get_cme_error(p_response)) {
2528 case CME_SUCCESS:
2529 break;
2530
2531 case CME_SIM_NOT_INSERTED:
2532 ret = SIM_ABSENT;
2533 goto done;
2534
2535 default:
2536 ret = SIM_NOT_READY;
2537 goto done;
2538 }
2539
2540 /* CPIN? has succeeded, now look at the result */
2541
2542 cpinLine = p_response->p_intermediates->line;
2543 err = at_tok_start (&cpinLine);
2544
2545 if (err < 0) {
2546 ret = SIM_NOT_READY;
2547 goto done;
2548 }
2549
2550 err = at_tok_nextstr(&cpinLine, &cpinResult);
2551
2552 if (err < 0) {
2553 ret = SIM_NOT_READY;
2554 goto done;
2555 }
2556
2557 if (0 == strcmp (cpinResult, "SIM PIN")) {
2558 ret = SIM_PIN;
2559 goto done;
2560 } else if (0 == strcmp (cpinResult, "SIM PUK")) {
2561 ret = SIM_PUK;
2562 goto done;
2563 } else if (0 == strcmp (cpinResult, "PH-NET PIN")) {
2564 return SIM_NETWORK_PERSONALIZATION;
2565 } else if (0 != strcmp (cpinResult, "READY")) {
2566 /* we're treating unsupported lock types as "sim absent" */
2567 ret = SIM_ABSENT;
2568 goto done;
2569 }
2570
2571 at_response_free(p_response);
2572 p_response = NULL;
2573 cpinResult = NULL;
2574
2575 ret = SIM_READY;
2576
2577done:
2578 at_response_free(p_response);
2579 return ret;
2580}
2581
John Wang309ac292009-07-30 14:53:23 -07002582/** Returns SIM_NOT_READY on error */
David 'Digit' Turneraf1298d2011-02-04 13:36:47 +01002583static SIM_Status
The Android Open Source Project00f06fc2009-03-03 19:32:15 -08002584getSIMStatus()
2585{
2586 ATResponse *p_response = NULL;
2587 int err;
2588 int ret;
2589 char *cpinLine;
2590 char *cpinResult;
2591
Wink Saville4dcab4f2012-11-19 16:05:13 -08002592 RLOGD("getSIMStatus(). sState: %d",sState);
The Android Open Source Project00f06fc2009-03-03 19:32:15 -08002593 if (sState == RADIO_STATE_OFF || sState == RADIO_STATE_UNAVAILABLE) {
John Wang309ac292009-07-30 14:53:23 -07002594 ret = SIM_NOT_READY;
The Android Open Source Project00f06fc2009-03-03 19:32:15 -08002595 goto done;
2596 }
2597
2598 err = at_send_command_singleline("AT+CPIN?", "+CPIN:", &p_response);
2599
2600 if (err != 0) {
John Wang309ac292009-07-30 14:53:23 -07002601 ret = SIM_NOT_READY;
The Android Open Source Project00f06fc2009-03-03 19:32:15 -08002602 goto done;
2603 }
2604
2605 switch (at_get_cme_error(p_response)) {
2606 case CME_SUCCESS:
2607 break;
2608
2609 case CME_SIM_NOT_INSERTED:
John Wang309ac292009-07-30 14:53:23 -07002610 ret = SIM_ABSENT;
The Android Open Source Project00f06fc2009-03-03 19:32:15 -08002611 goto done;
2612
2613 default:
John Wang309ac292009-07-30 14:53:23 -07002614 ret = SIM_NOT_READY;
The Android Open Source Project00f06fc2009-03-03 19:32:15 -08002615 goto done;
2616 }
2617
2618 /* CPIN? has succeeded, now look at the result */
2619
2620 cpinLine = p_response->p_intermediates->line;
2621 err = at_tok_start (&cpinLine);
2622
2623 if (err < 0) {
John Wang309ac292009-07-30 14:53:23 -07002624 ret = SIM_NOT_READY;
The Android Open Source Project00f06fc2009-03-03 19:32:15 -08002625 goto done;
2626 }
2627
2628 err = at_tok_nextstr(&cpinLine, &cpinResult);
2629
2630 if (err < 0) {
John Wang309ac292009-07-30 14:53:23 -07002631 ret = SIM_NOT_READY;
The Android Open Source Project00f06fc2009-03-03 19:32:15 -08002632 goto done;
2633 }
2634
2635 if (0 == strcmp (cpinResult, "SIM PIN")) {
John Wang309ac292009-07-30 14:53:23 -07002636 ret = SIM_PIN;
The Android Open Source Project00f06fc2009-03-03 19:32:15 -08002637 goto done;
2638 } else if (0 == strcmp (cpinResult, "SIM PUK")) {
John Wang309ac292009-07-30 14:53:23 -07002639 ret = SIM_PUK;
The Android Open Source Project00f06fc2009-03-03 19:32:15 -08002640 goto done;
2641 } else if (0 == strcmp (cpinResult, "PH-NET PIN")) {
John Wang309ac292009-07-30 14:53:23 -07002642 return SIM_NETWORK_PERSONALIZATION;
The Android Open Source Project00f06fc2009-03-03 19:32:15 -08002643 } else if (0 != strcmp (cpinResult, "READY")) {
2644 /* we're treating unsupported lock types as "sim absent" */
John Wang309ac292009-07-30 14:53:23 -07002645 ret = SIM_ABSENT;
The Android Open Source Project00f06fc2009-03-03 19:32:15 -08002646 goto done;
2647 }
2648
2649 at_response_free(p_response);
2650 p_response = NULL;
2651 cpinResult = NULL;
2652
John Wang309ac292009-07-30 14:53:23 -07002653 ret = SIM_READY;
The Android Open Source Project00f06fc2009-03-03 19:32:15 -08002654
2655done:
2656 at_response_free(p_response);
2657 return ret;
2658}
2659
2660
2661/**
Wink Savillef6aa7c12009-04-30 14:20:52 -07002662 * Get the current card status.
2663 *
2664 * This must be freed using freeCardStatus.
2665 * @return: On success returns RIL_E_SUCCESS
2666 */
Wink Saville2c1fb3a2011-03-19 13:42:45 -07002667static int getCardStatus(RIL_CardStatus_v6 **pp_card_status) {
Wink Savillef6aa7c12009-04-30 14:20:52 -07002668 static RIL_AppStatus app_status_array[] = {
John Wang309ac292009-07-30 14:53:23 -07002669 // SIM_ABSENT = 0
Wink Savillef6aa7c12009-04-30 14:20:52 -07002670 { RIL_APPTYPE_UNKNOWN, RIL_APPSTATE_UNKNOWN, RIL_PERSOSUBSTATE_UNKNOWN,
2671 NULL, NULL, 0, RIL_PINSTATE_UNKNOWN, RIL_PINSTATE_UNKNOWN },
John Wang309ac292009-07-30 14:53:23 -07002672 // SIM_NOT_READY = 1
Wink Savillef6aa7c12009-04-30 14:20:52 -07002673 { RIL_APPTYPE_SIM, RIL_APPSTATE_DETECTED, RIL_PERSOSUBSTATE_UNKNOWN,
2674 NULL, NULL, 0, RIL_PINSTATE_UNKNOWN, RIL_PINSTATE_UNKNOWN },
John Wang309ac292009-07-30 14:53:23 -07002675 // SIM_READY = 2
Wink Savillef6aa7c12009-04-30 14:20:52 -07002676 { RIL_APPTYPE_SIM, RIL_APPSTATE_READY, RIL_PERSOSUBSTATE_READY,
2677 NULL, NULL, 0, RIL_PINSTATE_UNKNOWN, RIL_PINSTATE_UNKNOWN },
John Wang309ac292009-07-30 14:53:23 -07002678 // SIM_PIN = 3
Wink Savillef6aa7c12009-04-30 14:20:52 -07002679 { RIL_APPTYPE_SIM, RIL_APPSTATE_PIN, RIL_PERSOSUBSTATE_UNKNOWN,
2680 NULL, NULL, 0, RIL_PINSTATE_ENABLED_NOT_VERIFIED, RIL_PINSTATE_UNKNOWN },
John Wang309ac292009-07-30 14:53:23 -07002681 // SIM_PUK = 4
Wink Savillef6aa7c12009-04-30 14:20:52 -07002682 { RIL_APPTYPE_SIM, RIL_APPSTATE_PUK, RIL_PERSOSUBSTATE_UNKNOWN,
2683 NULL, NULL, 0, RIL_PINSTATE_ENABLED_BLOCKED, RIL_PINSTATE_UNKNOWN },
John Wang309ac292009-07-30 14:53:23 -07002684 // SIM_NETWORK_PERSONALIZATION = 5
Wink Savillef6aa7c12009-04-30 14:20:52 -07002685 { RIL_APPTYPE_SIM, RIL_APPSTATE_SUBSCRIPTION_PERSO, RIL_PERSOSUBSTATE_SIM_NETWORK,
Jaime A Lopez-Sollanoe9645042012-08-29 07:27:27 -07002686 NULL, NULL, 0, RIL_PINSTATE_ENABLED_NOT_VERIFIED, RIL_PINSTATE_UNKNOWN },
2687 // RUIM_ABSENT = 6
2688 { RIL_APPTYPE_UNKNOWN, RIL_APPSTATE_UNKNOWN, RIL_PERSOSUBSTATE_UNKNOWN,
2689 NULL, NULL, 0, RIL_PINSTATE_UNKNOWN, RIL_PINSTATE_UNKNOWN },
2690 // RUIM_NOT_READY = 7
2691 { RIL_APPTYPE_RUIM, RIL_APPSTATE_DETECTED, RIL_PERSOSUBSTATE_UNKNOWN,
2692 NULL, NULL, 0, RIL_PINSTATE_UNKNOWN, RIL_PINSTATE_UNKNOWN },
2693 // RUIM_READY = 8
2694 { RIL_APPTYPE_RUIM, RIL_APPSTATE_READY, RIL_PERSOSUBSTATE_READY,
2695 NULL, NULL, 0, RIL_PINSTATE_UNKNOWN, RIL_PINSTATE_UNKNOWN },
2696 // RUIM_PIN = 9
2697 { RIL_APPTYPE_RUIM, RIL_APPSTATE_PIN, RIL_PERSOSUBSTATE_UNKNOWN,
2698 NULL, NULL, 0, RIL_PINSTATE_ENABLED_NOT_VERIFIED, RIL_PINSTATE_UNKNOWN },
2699 // RUIM_PUK = 10
2700 { RIL_APPTYPE_RUIM, RIL_APPSTATE_PUK, RIL_PERSOSUBSTATE_UNKNOWN,
2701 NULL, NULL, 0, RIL_PINSTATE_ENABLED_BLOCKED, RIL_PINSTATE_UNKNOWN },
2702 // RUIM_NETWORK_PERSONALIZATION = 11
2703 { RIL_APPTYPE_RUIM, RIL_APPSTATE_SUBSCRIPTION_PERSO, RIL_PERSOSUBSTATE_SIM_NETWORK,
2704 NULL, NULL, 0, RIL_PINSTATE_ENABLED_NOT_VERIFIED, RIL_PINSTATE_UNKNOWN }
Wink Savillef6aa7c12009-04-30 14:20:52 -07002705 };
2706 RIL_CardState card_state;
2707 int num_apps;
2708
2709 int sim_status = getSIMStatus();
John Wang309ac292009-07-30 14:53:23 -07002710 if (sim_status == SIM_ABSENT) {
Wink Savillef6aa7c12009-04-30 14:20:52 -07002711 card_state = RIL_CARDSTATE_ABSENT;
2712 num_apps = 0;
2713 } else {
2714 card_state = RIL_CARDSTATE_PRESENT;
Jaime A Lopez-Sollanoe9645042012-08-29 07:27:27 -07002715 num_apps = 2;
Wink Savillef6aa7c12009-04-30 14:20:52 -07002716 }
2717
2718 // Allocate and initialize base card status.
Wink Saville2c1fb3a2011-03-19 13:42:45 -07002719 RIL_CardStatus_v6 *p_card_status = malloc(sizeof(RIL_CardStatus_v6));
Wink Savillef6aa7c12009-04-30 14:20:52 -07002720 p_card_status->card_state = card_state;
2721 p_card_status->universal_pin_state = RIL_PINSTATE_UNKNOWN;
2722 p_card_status->gsm_umts_subscription_app_index = RIL_CARD_MAX_APPS;
2723 p_card_status->cdma_subscription_app_index = RIL_CARD_MAX_APPS;
Wink Saville2c1fb3a2011-03-19 13:42:45 -07002724 p_card_status->ims_subscription_app_index = RIL_CARD_MAX_APPS;
Wink Savillef6aa7c12009-04-30 14:20:52 -07002725 p_card_status->num_applications = num_apps;
2726
2727 // Initialize application status
2728 int i;
2729 for (i = 0; i < RIL_CARD_MAX_APPS; i++) {
John Wang309ac292009-07-30 14:53:23 -07002730 p_card_status->applications[i] = app_status_array[SIM_ABSENT];
Wink Savillef6aa7c12009-04-30 14:20:52 -07002731 }
2732
2733 // Pickup the appropriate application status
2734 // that reflects sim_status for gsm.
2735 if (num_apps != 0) {
2736 // Only support one app, gsm
Jaime A Lopez-Sollanoe9645042012-08-29 07:27:27 -07002737 p_card_status->num_applications = 2;
Wink Savillef6aa7c12009-04-30 14:20:52 -07002738 p_card_status->gsm_umts_subscription_app_index = 0;
Jaime A Lopez-Sollanoe9645042012-08-29 07:27:27 -07002739 p_card_status->cdma_subscription_app_index = 1;
Wink Savillef6aa7c12009-04-30 14:20:52 -07002740
2741 // Get the correct app status
2742 p_card_status->applications[0] = app_status_array[sim_status];
Jaime A Lopez-Sollanoe9645042012-08-29 07:27:27 -07002743 p_card_status->applications[1] = app_status_array[sim_status + RUIM_ABSENT];
Wink Savillef6aa7c12009-04-30 14:20:52 -07002744 }
2745
2746 *pp_card_status = p_card_status;
2747 return RIL_E_SUCCESS;
2748}
2749
2750/**
2751 * Free the card status returned by getCardStatus
2752 */
Wink Saville2c1fb3a2011-03-19 13:42:45 -07002753static void freeCardStatus(RIL_CardStatus_v6 *p_card_status) {
Wink Savillef6aa7c12009-04-30 14:20:52 -07002754 free(p_card_status);
2755}
2756
2757/**
The Android Open Source Project00f06fc2009-03-03 19:32:15 -08002758 * SIM ready means any commands that access the SIM will work, including:
2759 * AT+CPIN, AT+CSMS, AT+CNMI, AT+CRSM
2760 * (all SMS-related commands)
2761 */
2762
Mark Salyzynba58c202014-03-12 15:20:22 -07002763static void pollSIMState (void *param __unused)
The Android Open Source Project00f06fc2009-03-03 19:32:15 -08002764{
2765 ATResponse *p_response;
2766 int ret;
2767
2768 if (sState != RADIO_STATE_SIM_NOT_READY) {
2769 // no longer valid to poll
2770 return;
2771 }
2772
2773 switch(getSIMStatus()) {
John Wang309ac292009-07-30 14:53:23 -07002774 case SIM_ABSENT:
2775 case SIM_PIN:
2776 case SIM_PUK:
2777 case SIM_NETWORK_PERSONALIZATION:
The Android Open Source Project00f06fc2009-03-03 19:32:15 -08002778 default:
Wink Saville4dcab4f2012-11-19 16:05:13 -08002779 RLOGI("SIM ABSENT or LOCKED");
Jaime A Lopez-Sollanoe9645042012-08-29 07:27:27 -07002780 RIL_onUnsolicitedResponse(RIL_UNSOL_RESPONSE_SIM_STATUS_CHANGED, NULL, 0);
The Android Open Source Project00f06fc2009-03-03 19:32:15 -08002781 return;
2782
John Wang309ac292009-07-30 14:53:23 -07002783 case SIM_NOT_READY:
The Android Open Source Project00f06fc2009-03-03 19:32:15 -08002784 RIL_requestTimedCallback (pollSIMState, NULL, &TIMEVAL_SIMPOLL);
2785 return;
2786
John Wang309ac292009-07-30 14:53:23 -07002787 case SIM_READY:
Wink Saville4dcab4f2012-11-19 16:05:13 -08002788 RLOGI("SIM_READY");
Jaime A Lopez-Sollanoe9645042012-08-29 07:27:27 -07002789 onSIMReady();
2790 RIL_onUnsolicitedResponse(RIL_UNSOL_RESPONSE_SIM_STATUS_CHANGED, NULL, 0);
The Android Open Source Project00f06fc2009-03-03 19:32:15 -08002791 return;
2792 }
2793}
2794
2795/** returns 1 if on, 0 if off, and -1 on error */
2796static int isRadioOn()
2797{
2798 ATResponse *p_response = NULL;
2799 int err;
2800 char *line;
2801 char ret;
2802
2803 err = at_send_command_singleline("AT+CFUN?", "+CFUN:", &p_response);
2804
2805 if (err < 0 || p_response->success == 0) {
2806 // assume radio is off
2807 goto error;
2808 }
2809
2810 line = p_response->p_intermediates->line;
2811
2812 err = at_tok_start(&line);
2813 if (err < 0) goto error;
2814
2815 err = at_tok_nextbool(&line, &ret);
2816 if (err < 0) goto error;
2817
2818 at_response_free(p_response);
2819
2820 return (int)ret;
2821
2822error:
2823
2824 at_response_free(p_response);
2825 return -1;
2826}
2827
2828/**
Jaime A Lopez-Sollanoe9645042012-08-29 07:27:27 -07002829 * Parse the response generated by a +CTEC AT command
2830 * The values read from the response are stored in current and preferred.
2831 * Both current and preferred may be null. The corresponding value is ignored in that case.
2832 *
2833 * @return: -1 if some error occurs (or if the modem doesn't understand the +CTEC command)
2834 * 1 if the response includes the current technology only
2835 * 0 if the response includes both current technology and preferred mode
2836 */
2837int parse_technology_response( const char *response, int *current, int32_t *preferred )
2838{
2839 int err;
2840 char *line, *p;
2841 int ct;
2842 int32_t pt = 0;
2843 char *str_pt;
2844
2845 line = p = strdup(response);
Wink Saville4dcab4f2012-11-19 16:05:13 -08002846 RLOGD("Response: %s", line);
Jaime A Lopez-Sollanoe9645042012-08-29 07:27:27 -07002847 err = at_tok_start(&p);
2848 if (err || !at_tok_hasmore(&p)) {
Wink Saville4dcab4f2012-11-19 16:05:13 -08002849 RLOGD("err: %d. p: %s", err, p);
Jaime A Lopez-Sollanoe9645042012-08-29 07:27:27 -07002850 free(line);
2851 return -1;
2852 }
2853
2854 err = at_tok_nextint(&p, &ct);
2855 if (err) {
2856 free(line);
2857 return -1;
2858 }
2859 if (current) *current = ct;
2860
Wink Saville4dcab4f2012-11-19 16:05:13 -08002861 RLOGD("line remaining after int: %s", p);
Jaime A Lopez-Sollanoe9645042012-08-29 07:27:27 -07002862
2863 err = at_tok_nexthexint(&p, &pt);
2864 if (err) {
2865 free(line);
2866 return 1;
2867 }
2868 if (preferred) {
2869 *preferred = pt;
2870 }
2871 free(line);
2872
2873 return 0;
2874}
2875
Mark Salyzynba58c202014-03-12 15:20:22 -07002876int query_supported_techs( ModemInfo *mdm __unused, int *supported )
Jaime A Lopez-Sollanoe9645042012-08-29 07:27:27 -07002877{
2878 ATResponse *p_response;
2879 int err, val, techs = 0;
2880 char *tok;
2881 char *line;
2882
Wink Saville4dcab4f2012-11-19 16:05:13 -08002883 RLOGD("query_supported_techs");
Jaime A Lopez-Sollanoe9645042012-08-29 07:27:27 -07002884 err = at_send_command_singleline("AT+CTEC=?", "+CTEC:", &p_response);
2885 if (err || !p_response->success)
2886 goto error;
2887 line = p_response->p_intermediates->line;
2888 err = at_tok_start(&line);
2889 if (err || !at_tok_hasmore(&line))
2890 goto error;
2891 while (!at_tok_nextint(&line, &val)) {
2892 techs |= ( 1 << val );
2893 }
2894 if (supported) *supported = techs;
2895 return 0;
2896error:
2897 at_response_free(p_response);
2898 return -1;
2899}
2900
2901/**
2902 * query_ctec. Send the +CTEC AT command to the modem to query the current
2903 * and preferred modes. It leaves values in the addresses pointed to by
2904 * current and preferred. If any of those pointers are NULL, the corresponding value
2905 * is ignored, but the return value will still reflect if retreiving and parsing of the
2906 * values suceeded.
2907 *
2908 * @mdm Currently unused
2909 * @current A pointer to store the current mode returned by the modem. May be null.
2910 * @preferred A pointer to store the preferred mode returned by the modem. May be null.
2911 * @return -1 on error (or failure to parse)
2912 * 1 if only the current mode was returned by modem (or failed to parse preferred)
2913 * 0 if both current and preferred were returned correctly
2914 */
Mark Salyzynba58c202014-03-12 15:20:22 -07002915int query_ctec(ModemInfo *mdm __unused, int *current, int32_t *preferred)
Jaime A Lopez-Sollanoe9645042012-08-29 07:27:27 -07002916{
2917 ATResponse *response = NULL;
2918 int err;
2919 int res;
2920
Colin Cross5cba4882014-02-05 18:55:42 -08002921 RLOGD("query_ctec. current: %p, preferred: %p", current, preferred);
Jaime A Lopez-Sollanoe9645042012-08-29 07:27:27 -07002922 err = at_send_command_singleline("AT+CTEC?", "+CTEC:", &response);
2923 if (!err && response->success) {
2924 res = parse_technology_response(response->p_intermediates->line, current, preferred);
2925 at_response_free(response);
2926 return res;
2927 }
Colin Cross5cba4882014-02-05 18:55:42 -08002928 RLOGE("Error executing command: %d. response: %p. status: %d", err, response, response? response->success : -1);
Jaime A Lopez-Sollanoe9645042012-08-29 07:27:27 -07002929 at_response_free(response);
2930 return -1;
2931}
2932
2933int is_multimode_modem(ModemInfo *mdm)
2934{
2935 ATResponse *response;
2936 int err;
2937 char *line;
2938 int tech;
2939 int32_t preferred;
2940
2941 if (query_ctec(mdm, &tech, &preferred) == 0) {
2942 mdm->currentTech = tech;
2943 mdm->preferredNetworkMode = preferred;
2944 if (query_supported_techs(mdm, &mdm->supportedTechs)) {
2945 return 0;
2946 }
2947 return 1;
2948 }
2949 return 0;
2950}
2951
2952/**
2953 * Find out if our modem is GSM, CDMA or both (Multimode)
2954 */
2955static void probeForModemMode(ModemInfo *info)
2956{
2957 ATResponse *response;
2958 int err;
2959 assert (info);
2960 // Currently, our only known multimode modem is qemu's android modem,
2961 // which implements the AT+CTEC command to query and set mode.
2962 // Try that first
2963
2964 if (is_multimode_modem(info)) {
Wink Saville4dcab4f2012-11-19 16:05:13 -08002965 RLOGI("Found Multimode Modem. Supported techs mask: %8.8x. Current tech: %d",
Jaime A Lopez-Sollanoe9645042012-08-29 07:27:27 -07002966 info->supportedTechs, info->currentTech);
2967 return;
2968 }
2969
2970 /* Being here means that our modem is not multimode */
2971 info->isMultimode = 0;
2972
2973 /* CDMA Modems implement the AT+WNAM command */
2974 err = at_send_command_singleline("AT+WNAM","+WNAM:", &response);
2975 if (!err && response->success) {
2976 at_response_free(response);
2977 // TODO: find out if we really support EvDo
2978 info->supportedTechs = MDM_CDMA | MDM_EVDO;
2979 info->currentTech = MDM_CDMA;
Wink Saville4dcab4f2012-11-19 16:05:13 -08002980 RLOGI("Found CDMA Modem");
Jaime A Lopez-Sollanoe9645042012-08-29 07:27:27 -07002981 return;
2982 }
2983 if (!err) at_response_free(response);
2984 // TODO: find out if modem really supports WCDMA/LTE
2985 info->supportedTechs = MDM_GSM | MDM_WCDMA | MDM_LTE;
2986 info->currentTech = MDM_GSM;
Wink Saville4dcab4f2012-11-19 16:05:13 -08002987 RLOGI("Found GSM Modem");
Jaime A Lopez-Sollanoe9645042012-08-29 07:27:27 -07002988}
2989
2990/**
The Android Open Source Project00f06fc2009-03-03 19:32:15 -08002991 * Initialize everything that can be configured while we're still in
2992 * AT+CFUN=0
2993 */
Mark Salyzynba58c202014-03-12 15:20:22 -07002994static void initializeCallback(void *param __unused)
The Android Open Source Project00f06fc2009-03-03 19:32:15 -08002995{
2996 ATResponse *p_response = NULL;
2997 int err;
2998
2999 setRadioState (RADIO_STATE_OFF);
3000
3001 at_handshake();
3002
Jaime A Lopez-Sollanoe9645042012-08-29 07:27:27 -07003003 probeForModemMode(sMdmInfo);
The Android Open Source Project00f06fc2009-03-03 19:32:15 -08003004 /* note: we don't check errors here. Everything important will
3005 be handled in onATTimeout and onATReaderClosed */
3006
3007 /* atchannel is tolerant of echo but it must */
3008 /* have verbose result codes */
3009 at_send_command("ATE0Q0V1", NULL);
3010
3011 /* No auto-answer */
3012 at_send_command("ATS0=0", NULL);
3013
3014 /* Extended errors */
3015 at_send_command("AT+CMEE=1", NULL);
3016
3017 /* Network registration events */
3018 err = at_send_command("AT+CREG=2", &p_response);
3019
3020 /* some handsets -- in tethered mode -- don't support CREG=2 */
3021 if (err < 0 || p_response->success == 0) {
3022 at_send_command("AT+CREG=1", NULL);
3023 }
3024
3025 at_response_free(p_response);
3026
3027 /* GPRS registration events */
3028 at_send_command("AT+CGREG=1", NULL);
3029
3030 /* Call Waiting notifications */
3031 at_send_command("AT+CCWA=1", NULL);
3032
3033 /* Alternating voice/data off */
3034 at_send_command("AT+CMOD=0", NULL);
3035
3036 /* Not muted */
3037 at_send_command("AT+CMUT=0", NULL);
3038
3039 /* +CSSU unsolicited supp service notifications */
3040 at_send_command("AT+CSSN=0,1", NULL);
3041
3042 /* no connected line identification */
3043 at_send_command("AT+COLP=0", NULL);
3044
3045 /* HEX character set */
3046 at_send_command("AT+CSCS=\"HEX\"", NULL);
3047
3048 /* USSD unsolicited */
3049 at_send_command("AT+CUSD=1", NULL);
3050
3051 /* Enable +CGEV GPRS event notifications, but don't buffer */
3052 at_send_command("AT+CGEREP=1,0", NULL);
3053
3054 /* SMS PDU mode */
3055 at_send_command("AT+CMGF=0", NULL);
3056
3057#ifdef USE_TI_COMMANDS
3058
3059 at_send_command("AT%CPI=3", NULL);
3060
3061 /* TI specific -- notifications when SMS is ready (currently ignored) */
3062 at_send_command("AT%CSTAT=1", NULL);
3063
3064#endif /* USE_TI_COMMANDS */
3065
3066
3067 /* assume radio is off on error */
3068 if (isRadioOn() > 0) {
Jaime A Lopez-Sollanoe9645042012-08-29 07:27:27 -07003069 setRadioState (RADIO_STATE_ON);
The Android Open Source Project00f06fc2009-03-03 19:32:15 -08003070 }
3071}
3072
3073static void waitForClose()
3074{
3075 pthread_mutex_lock(&s_state_mutex);
3076
3077 while (s_closed == 0) {
3078 pthread_cond_wait(&s_state_cond, &s_state_mutex);
3079 }
3080
3081 pthread_mutex_unlock(&s_state_mutex);
3082}
3083
Sukanya Rajkhowaa18b9d12013-09-10 12:30:13 -07003084static void sendUnsolImsNetworkStateChanged()
3085{
3086#if 0 // to be used when unsol is changed to return data.
3087 int reply[2];
3088 reply[0] = s_ims_registered;
3089 reply[1] = s_ims_services;
3090 reply[1] = s_ims_format;
3091#endif
3092 RIL_onUnsolicitedResponse(RIL_UNSOL_RESPONSE_IMS_NETWORK_STATE_CHANGED,
3093 NULL, 0);
3094}
3095
The Android Open Source Project00f06fc2009-03-03 19:32:15 -08003096/**
3097 * Called by atchannel when an unsolicited line appears
3098 * This is called on atchannel's reader thread. AT commands may
3099 * not be issued here
3100 */
3101static void onUnsolicited (const char *s, const char *sms_pdu)
3102{
Jaime A Lopez-Sollanoe9645042012-08-29 07:27:27 -07003103 char *line = NULL, *p;
The Android Open Source Project00f06fc2009-03-03 19:32:15 -08003104 int err;
3105
3106 /* Ignore unsolicited responses until we're initialized.
3107 * This is OK because the RIL library will poll for initial state
3108 */
3109 if (sState == RADIO_STATE_UNAVAILABLE) {
3110 return;
3111 }
3112
3113 if (strStartsWith(s, "%CTZV:")) {
3114 /* TI specific -- NITZ time */
3115 char *response;
3116
Jaime A Lopez-Sollanoe9645042012-08-29 07:27:27 -07003117 line = p = strdup(s);
3118 at_tok_start(&p);
The Android Open Source Project00f06fc2009-03-03 19:32:15 -08003119
Jaime A Lopez-Sollanoe9645042012-08-29 07:27:27 -07003120 err = at_tok_nextstr(&p, &response);
The Android Open Source Project00f06fc2009-03-03 19:32:15 -08003121
3122 if (err != 0) {
Wink Saville4dcab4f2012-11-19 16:05:13 -08003123 RLOGE("invalid NITZ line %s\n", s);
The Android Open Source Project00f06fc2009-03-03 19:32:15 -08003124 } else {
3125 RIL_onUnsolicitedResponse (
3126 RIL_UNSOL_NITZ_TIME_RECEIVED,
3127 response, strlen(response));
3128 }
Ivan Krasine18b85c2016-01-27 11:17:58 -08003129 free(line);
The Android Open Source Project00f06fc2009-03-03 19:32:15 -08003130 } else if (strStartsWith(s,"+CRING:")
3131 || strStartsWith(s,"RING")
3132 || strStartsWith(s,"NO CARRIER")
3133 || strStartsWith(s,"+CCWA")
3134 ) {
3135 RIL_onUnsolicitedResponse (
3136 RIL_UNSOL_RESPONSE_CALL_STATE_CHANGED,
3137 NULL, 0);
3138#ifdef WORKAROUND_FAKE_CGEV
Wink Savillef4c4d362009-04-02 01:37:03 -07003139 RIL_requestTimedCallback (onDataCallListChanged, NULL, NULL); //TODO use new function
The Android Open Source Project00f06fc2009-03-03 19:32:15 -08003140#endif /* WORKAROUND_FAKE_CGEV */
3141 } else if (strStartsWith(s,"+CREG:")
3142 || strStartsWith(s,"+CGREG:")
3143 ) {
3144 RIL_onUnsolicitedResponse (
Wink Saville2c1fb3a2011-03-19 13:42:45 -07003145 RIL_UNSOL_RESPONSE_VOICE_NETWORK_STATE_CHANGED,
The Android Open Source Project00f06fc2009-03-03 19:32:15 -08003146 NULL, 0);
3147#ifdef WORKAROUND_FAKE_CGEV
Wink Saville7f856802009-06-09 10:23:37 -07003148 RIL_requestTimedCallback (onDataCallListChanged, NULL, NULL);
The Android Open Source Project00f06fc2009-03-03 19:32:15 -08003149#endif /* WORKAROUND_FAKE_CGEV */
3150 } else if (strStartsWith(s, "+CMT:")) {
3151 RIL_onUnsolicitedResponse (
3152 RIL_UNSOL_RESPONSE_NEW_SMS,
3153 sms_pdu, strlen(sms_pdu));
3154 } else if (strStartsWith(s, "+CDS:")) {
3155 RIL_onUnsolicitedResponse (
3156 RIL_UNSOL_RESPONSE_NEW_SMS_STATUS_REPORT,
3157 sms_pdu, strlen(sms_pdu));
3158 } else if (strStartsWith(s, "+CGEV:")) {
3159 /* Really, we can ignore NW CLASS and ME CLASS events here,
3160 * but right now we don't since extranous
Wink Savillef4c4d362009-04-02 01:37:03 -07003161 * RIL_UNSOL_DATA_CALL_LIST_CHANGED calls are tolerated
The Android Open Source Project00f06fc2009-03-03 19:32:15 -08003162 */
3163 /* can't issue AT commands here -- call on main thread */
Wink Savillef4c4d362009-04-02 01:37:03 -07003164 RIL_requestTimedCallback (onDataCallListChanged, NULL, NULL);
The Android Open Source Project00f06fc2009-03-03 19:32:15 -08003165#ifdef WORKAROUND_FAKE_CGEV
3166 } else if (strStartsWith(s, "+CME ERROR: 150")) {
Wink Savillef4c4d362009-04-02 01:37:03 -07003167 RIL_requestTimedCallback (onDataCallListChanged, NULL, NULL);
The Android Open Source Project00f06fc2009-03-03 19:32:15 -08003168#endif /* WORKAROUND_FAKE_CGEV */
Jaime A Lopez-Sollanoe9645042012-08-29 07:27:27 -07003169 } else if (strStartsWith(s, "+CTEC: ")) {
3170 int tech, mask;
3171 switch (parse_technology_response(s, &tech, NULL))
3172 {
3173 case -1: // no argument could be parsed.
Wink Saville4dcab4f2012-11-19 16:05:13 -08003174 RLOGE("invalid CTEC line %s\n", s);
Jaime A Lopez-Sollanoe9645042012-08-29 07:27:27 -07003175 break;
3176 case 1: // current mode correctly parsed
3177 case 0: // preferred mode correctly parsed
3178 mask = 1 << tech;
3179 if (mask != MDM_GSM && mask != MDM_CDMA &&
3180 mask != MDM_WCDMA && mask != MDM_LTE) {
Wink Saville4dcab4f2012-11-19 16:05:13 -08003181 RLOGE("Unknown technology %d\n", tech);
Jaime A Lopez-Sollanoe9645042012-08-29 07:27:27 -07003182 } else {
3183 setRadioTechnology(sMdmInfo, tech);
3184 }
3185 break;
3186 }
3187 } else if (strStartsWith(s, "+CCSS: ")) {
3188 int source = 0;
3189 line = p = strdup(s);
3190 if (!line) {
Wink Saville4dcab4f2012-11-19 16:05:13 -08003191 RLOGE("+CCSS: Unable to allocate memory");
Jaime A Lopez-Sollanoe9645042012-08-29 07:27:27 -07003192 return;
3193 }
3194 if (at_tok_start(&p) < 0) {
3195 free(line);
3196 return;
3197 }
3198 if (at_tok_nextint(&p, &source) < 0) {
Wink Saville4dcab4f2012-11-19 16:05:13 -08003199 RLOGE("invalid +CCSS response: %s", line);
Jaime A Lopez-Sollanoe9645042012-08-29 07:27:27 -07003200 free(line);
3201 return;
3202 }
3203 SSOURCE(sMdmInfo) = source;
3204 RIL_onUnsolicitedResponse(RIL_UNSOL_CDMA_SUBSCRIPTION_SOURCE_CHANGED,
3205 &source, sizeof(source));
3206 } else if (strStartsWith(s, "+WSOS: ")) {
3207 char state = 0;
3208 int unsol;
3209 line = p = strdup(s);
3210 if (!line) {
Wink Saville4dcab4f2012-11-19 16:05:13 -08003211 RLOGE("+WSOS: Unable to allocate memory");
Jaime A Lopez-Sollanoe9645042012-08-29 07:27:27 -07003212 return;
3213 }
3214 if (at_tok_start(&p) < 0) {
3215 free(line);
3216 return;
3217 }
3218 if (at_tok_nextbool(&p, &state) < 0) {
Wink Saville4dcab4f2012-11-19 16:05:13 -08003219 RLOGE("invalid +WSOS response: %s", line);
Jaime A Lopez-Sollanoe9645042012-08-29 07:27:27 -07003220 free(line);
3221 return;
3222 }
3223 free(line);
3224
3225 unsol = state ?
3226 RIL_UNSOL_ENTER_EMERGENCY_CALLBACK_MODE : RIL_UNSOL_EXIT_EMERGENCY_CALLBACK_MODE;
3227
3228 RIL_onUnsolicitedResponse(unsol, NULL, 0);
3229
3230 } else if (strStartsWith(s, "+WPRL: ")) {
3231 int version = -1;
3232 line = p = strdup(s);
3233 if (!line) {
Wink Saville4dcab4f2012-11-19 16:05:13 -08003234 RLOGE("+WPRL: Unable to allocate memory");
Jaime A Lopez-Sollanoe9645042012-08-29 07:27:27 -07003235 return;
3236 }
3237 if (at_tok_start(&p) < 0) {
Wink Saville4dcab4f2012-11-19 16:05:13 -08003238 RLOGE("invalid +WPRL response: %s", s);
Jaime A Lopez-Sollanoe9645042012-08-29 07:27:27 -07003239 free(line);
3240 return;
3241 }
3242 if (at_tok_nextint(&p, &version) < 0) {
Wink Saville4dcab4f2012-11-19 16:05:13 -08003243 RLOGE("invalid +WPRL response: %s", s);
Jaime A Lopez-Sollanoe9645042012-08-29 07:27:27 -07003244 free(line);
3245 return;
3246 }
3247 free(line);
3248 RIL_onUnsolicitedResponse(RIL_UNSOL_CDMA_PRL_CHANGED, &version, sizeof(version));
3249 } else if (strStartsWith(s, "+CFUN: 0")) {
3250 setRadioState(RADIO_STATE_OFF);
The Android Open Source Project00f06fc2009-03-03 19:32:15 -08003251 }
3252}
3253
3254/* Called on command or reader thread */
3255static void onATReaderClosed()
3256{
Wink Saville4dcab4f2012-11-19 16:05:13 -08003257 RLOGI("AT channel closed\n");
The Android Open Source Project00f06fc2009-03-03 19:32:15 -08003258 at_close();
3259 s_closed = 1;
3260
3261 setRadioState (RADIO_STATE_UNAVAILABLE);
3262}
3263
3264/* Called on command thread */
3265static void onATTimeout()
3266{
Wink Saville4dcab4f2012-11-19 16:05:13 -08003267 RLOGI("AT channel timeout; closing\n");
The Android Open Source Project00f06fc2009-03-03 19:32:15 -08003268 at_close();
3269
3270 s_closed = 1;
3271
3272 /* FIXME cause a radio reset here */
3273
3274 setRadioState (RADIO_STATE_UNAVAILABLE);
3275}
3276
Etan Cohend3652192014-06-20 08:28:44 -07003277/* Called to pass hardware configuration information to telephony
3278 * framework.
3279 */
3280static void setHardwareConfiguration(int num, RIL_HardwareConfig *cfg)
3281{
3282 RIL_onUnsolicitedResponse(RIL_UNSOL_HARDWARE_CONFIG_CHANGED, cfg, num*sizeof(*cfg));
3283}
3284
Sanket Padawef0c8ca72016-06-30 15:01:08 -07003285static void usage(char *s __unused)
The Android Open Source Project00f06fc2009-03-03 19:32:15 -08003286{
3287#ifdef RIL_SHLIB
3288 fprintf(stderr, "reference-ril requires: -p <tcp port> or -d /dev/tty_device\n");
3289#else
3290 fprintf(stderr, "usage: %s [-p <tcp port>] [-d /dev/tty_device]\n", s);
3291 exit(-1);
3292#endif
3293}
3294
3295static void *
Mark Salyzynba58c202014-03-12 15:20:22 -07003296mainLoop(void *param __unused)
The Android Open Source Project00f06fc2009-03-03 19:32:15 -08003297{
3298 int fd;
3299 int ret;
3300
3301 AT_DUMP("== ", "entering mainLoop()", -1 );
3302 at_set_on_reader_closed(onATReaderClosed);
3303 at_set_on_timeout(onATTimeout);
3304
3305 for (;;) {
3306 fd = -1;
3307 while (fd < 0) {
David 'Digit' Turner834eca82016-06-22 12:10:01 +02003308 if (isInEmulator()) {
3309 fd = qemu_pipe_open("pipe:qemud:gsm");
3310 } else if (s_port > 0) {
The Android Open Source Project00f06fc2009-03-03 19:32:15 -08003311 fd = socket_loopback_client(s_port, SOCK_STREAM);
3312 } else if (s_device_socket) {
David 'Digit' Turner834eca82016-06-22 12:10:01 +02003313 fd = socket_local_client(s_device_path,
3314 ANDROID_SOCKET_NAMESPACE_FILESYSTEM,
3315 SOCK_STREAM);
The Android Open Source Project00f06fc2009-03-03 19:32:15 -08003316 } else if (s_device_path != NULL) {
3317 fd = open (s_device_path, O_RDWR);
3318 if ( fd >= 0 && !memcmp( s_device_path, "/dev/ttyS", 9 ) ) {
3319 /* disable echo on serial ports */
3320 struct termios ios;
3321 tcgetattr( fd, &ios );
3322 ios.c_lflag = 0; /* disable ECHO, ICANON, etc... */
3323 tcsetattr( fd, TCSANOW, &ios );
3324 }
3325 }
3326
3327 if (fd < 0) {
3328 perror ("opening AT interface. retrying...");
3329 sleep(10);
3330 /* never returns */
3331 }
3332 }
3333
3334 s_closed = 0;
3335 ret = at_open(fd, onUnsolicited);
3336
3337 if (ret < 0) {
Wink Saville4dcab4f2012-11-19 16:05:13 -08003338 RLOGE ("AT error %d on at_open\n", ret);
The Android Open Source Project00f06fc2009-03-03 19:32:15 -08003339 return 0;
3340 }
3341
3342 RIL_requestTimedCallback(initializeCallback, NULL, &TIMEVAL_0);
3343
3344 // Give initializeCallback a chance to dispatched, since
3345 // we don't presently have a cancellation mechanism
3346 sleep(1);
3347
3348 waitForClose();
Wink Saville4dcab4f2012-11-19 16:05:13 -08003349 RLOGI("Re-opening after close");
The Android Open Source Project00f06fc2009-03-03 19:32:15 -08003350 }
3351}
3352
3353#ifdef RIL_SHLIB
3354
3355pthread_t s_tid_mainloop;
3356
3357const RIL_RadioFunctions *RIL_Init(const struct RIL_Env *env, int argc, char **argv)
3358{
3359 int ret;
3360 int fd = -1;
3361 int opt;
3362 pthread_attr_t attr;
3363
3364 s_rilenv = env;
3365
Sandeep Gutta11f27942014-07-10 05:00:25 +05303366 while ( -1 != (opt = getopt(argc, argv, "p:d:s:c:"))) {
The Android Open Source Project00f06fc2009-03-03 19:32:15 -08003367 switch (opt) {
3368 case 'p':
3369 s_port = atoi(optarg);
3370 if (s_port == 0) {
3371 usage(argv[0]);
3372 return NULL;
3373 }
Wink Saville4dcab4f2012-11-19 16:05:13 -08003374 RLOGI("Opening loopback port %d\n", s_port);
The Android Open Source Project00f06fc2009-03-03 19:32:15 -08003375 break;
3376
3377 case 'd':
3378 s_device_path = optarg;
Wink Saville4dcab4f2012-11-19 16:05:13 -08003379 RLOGI("Opening tty device %s\n", s_device_path);
The Android Open Source Project00f06fc2009-03-03 19:32:15 -08003380 break;
3381
3382 case 's':
3383 s_device_path = optarg;
3384 s_device_socket = 1;
Wink Saville4dcab4f2012-11-19 16:05:13 -08003385 RLOGI("Opening socket %s\n", s_device_path);
The Android Open Source Project00f06fc2009-03-03 19:32:15 -08003386 break;
3387
Sandeep Gutta11f27942014-07-10 05:00:25 +05303388 case 'c':
3389 RLOGI("Client id received %s\n", optarg);
3390 break;
3391
The Android Open Source Project00f06fc2009-03-03 19:32:15 -08003392 default:
3393 usage(argv[0]);
3394 return NULL;
3395 }
3396 }
3397
David 'Digit' Turner834eca82016-06-22 12:10:01 +02003398 if (s_port < 0 && s_device_path == NULL && !isInEmulator()) {
The Android Open Source Project00f06fc2009-03-03 19:32:15 -08003399 usage(argv[0]);
3400 return NULL;
3401 }
3402
Jaime A Lopez-Sollanoe9645042012-08-29 07:27:27 -07003403 sMdmInfo = calloc(1, sizeof(ModemInfo));
3404 if (!sMdmInfo) {
Wink Saville4dcab4f2012-11-19 16:05:13 -08003405 RLOGE("Unable to alloc memory for ModemInfo");
Jaime A Lopez-Sollanoe9645042012-08-29 07:27:27 -07003406 return NULL;
3407 }
The Android Open Source Project00f06fc2009-03-03 19:32:15 -08003408 pthread_attr_init (&attr);
3409 pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
3410 ret = pthread_create(&s_tid_mainloop, &attr, mainLoop, NULL);
3411
3412 return &s_callbacks;
3413}
3414#else /* RIL_SHLIB */
3415int main (int argc, char **argv)
3416{
3417 int ret;
3418 int fd = -1;
3419 int opt;
3420
3421 while ( -1 != (opt = getopt(argc, argv, "p:d:"))) {
3422 switch (opt) {
3423 case 'p':
3424 s_port = atoi(optarg);
3425 if (s_port == 0) {
3426 usage(argv[0]);
3427 }
Wink Saville4dcab4f2012-11-19 16:05:13 -08003428 RLOGI("Opening loopback port %d\n", s_port);
The Android Open Source Project00f06fc2009-03-03 19:32:15 -08003429 break;
3430
3431 case 'd':
3432 s_device_path = optarg;
Wink Saville4dcab4f2012-11-19 16:05:13 -08003433 RLOGI("Opening tty device %s\n", s_device_path);
The Android Open Source Project00f06fc2009-03-03 19:32:15 -08003434 break;
3435
3436 case 's':
3437 s_device_path = optarg;
3438 s_device_socket = 1;
Wink Saville4dcab4f2012-11-19 16:05:13 -08003439 RLOGI("Opening socket %s\n", s_device_path);
The Android Open Source Project00f06fc2009-03-03 19:32:15 -08003440 break;
3441
3442 default:
3443 usage(argv[0]);
3444 }
3445 }
3446
David 'Digit' Turner834eca82016-06-22 12:10:01 +02003447 if (s_port < 0 && s_device_path == NULL && !isInEmulator()) {
The Android Open Source Project00f06fc2009-03-03 19:32:15 -08003448 usage(argv[0]);
3449 }
3450
3451 RIL_register(&s_callbacks);
3452
3453 mainLoop(NULL);
3454
3455 return 0;
3456}
3457
3458#endif /* RIL_SHLIB */