blob: 16a279c63699147976b53b93fb3d226e525bcfd4 [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,
Naveen Kalla2baf7232016-10-11 13:49:20 -0700159 SIM_READY = 2,
John Wang309ac292009-07-30 14:53:23 -0700160 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
Daniele Palmasa5c743e2015-05-06 11:47:59 +02001587 free(cmd1);
1588 free(cmd2);
1589
The Android Open Source Project00f06fc2009-03-03 19:32:15 -08001590 if (err != 0 || p_response->success == 0) goto error;
1591
The Android Open Source Project00f06fc2009-03-03 19:32:15 -08001592 /* FIXME fill in messageRef and ackPDU */
Sukanya Rajkhowaa18b9d12013-09-10 12:30:13 -07001593 response.messageRef = 1;
The Android Open Source Project00f06fc2009-03-03 19:32:15 -08001594 RIL_onRequestComplete(t, RIL_E_SUCCESS, &response, sizeof(response));
1595 at_response_free(p_response);
1596
1597 return;
1598error:
Sukanya Rajkhowaa18b9d12013-09-10 12:30:13 -07001599 response.messageRef = -2;
1600 RIL_onRequestComplete(t, RIL_E_GENERIC_FAILURE, &response, sizeof(response));
The Android Open Source Project00f06fc2009-03-03 19:32:15 -08001601 at_response_free(p_response);
Sukanya Rajkhowaa18b9d12013-09-10 12:30:13 -07001602 return;
1603error2:
1604 // send retry error.
1605 response.messageRef = -1;
1606 RIL_onRequestComplete(t, RIL_E_SMS_SEND_FAIL_RETRY, &response, sizeof(response));
1607 at_response_free(p_response);
1608 return;
1609 }
1610
1611static void requestImsSendSMS(void *data, size_t datalen, RIL_Token t)
1612{
1613 RIL_IMS_SMS_Message *p_args;
1614 RIL_SMS_Response response;
1615
1616 memset(&response, 0, sizeof(response));
1617
Mark Salyzynba58c202014-03-12 15:20:22 -07001618 RLOGD("requestImsSendSMS: datalen=%zu, "
Sukanya Rajkhowaa18b9d12013-09-10 12:30:13 -07001619 "registered=%d, service=%d, format=%d, ims_perm_fail=%d, "
1620 "ims_retry=%d, gsm_fail=%d, gsm_retry=%d",
1621 datalen, s_ims_registered, s_ims_services, s_ims_format,
1622 s_ims_cause_perm_failure, s_ims_cause_retry, s_ims_gsm_fail,
1623 s_ims_gsm_retry);
1624
1625 // figure out if this is gsm/cdma format
1626 // then route it to requestSendSMS vs requestCdmaSendSMS respectively
1627 p_args = (RIL_IMS_SMS_Message *)data;
1628
1629 if (0 != s_ims_cause_perm_failure ) goto error;
1630
1631 // want to fail over ims and this is first request over ims
1632 if (0 != s_ims_cause_retry && 0 == p_args->retry) goto error2;
1633
1634 if (RADIO_TECH_3GPP == p_args->tech) {
1635 return requestSendSMS(p_args->message.gsmMessage,
1636 datalen - sizeof(RIL_RadioTechnologyFamily),
1637 t);
1638 } else if (RADIO_TECH_3GPP2 == p_args->tech) {
1639 return requestCdmaSendSMS(p_args->message.cdmaMessage,
1640 datalen - sizeof(RIL_RadioTechnologyFamily),
1641 t);
1642 } else {
1643 RLOGE("requestImsSendSMS invalid format value =%d", p_args->tech);
1644 }
1645
1646error:
1647 response.messageRef = -2;
1648 RIL_onRequestComplete(t, RIL_E_GENERIC_FAILURE, &response, sizeof(response));
1649 return;
1650
1651error2:
1652 response.messageRef = -1;
1653 RIL_onRequestComplete(t, RIL_E_SMS_SEND_FAIL_RETRY, &response, sizeof(response));
The Android Open Source Project00f06fc2009-03-03 19:32:15 -08001654}
1655
Wink Savillef4c4d362009-04-02 01:37:03 -07001656static void requestSetupDataCall(void *data, size_t datalen, RIL_Token t)
The Android Open Source Project00f06fc2009-03-03 19:32:15 -08001657{
1658 const char *apn;
1659 char *cmd;
1660 int err;
1661 ATResponse *p_response = NULL;
The Android Open Source Project00f06fc2009-03-03 19:32:15 -08001662
Wink Savillef4c4d362009-04-02 01:37:03 -07001663 apn = ((const char **)data)[2];
The Android Open Source Project00f06fc2009-03-03 19:32:15 -08001664
1665#ifdef USE_TI_COMMANDS
1666 // Config for multislot class 10 (probably default anyway eh?)
1667 err = at_send_command("AT%CPRIM=\"GMM\",\"CONFIG MULTISLOT_CLASS=<10>\"",
1668 NULL);
1669
1670 err = at_send_command("AT%DATA=2,\"UART\",1,,\"SER\",\"UART\",0", NULL);
1671#endif /* USE_TI_COMMANDS */
1672
1673 int fd, qmistatus;
1674 size_t cur = 0;
1675 size_t len;
1676 ssize_t written, rlen;
1677 char status[32] = {0};
1678 int retry = 10;
Lorenzo Colitti4f81dcf2010-09-01 19:38:57 -07001679 const char *pdp_type;
The Android Open Source Project00f06fc2009-03-03 19:32:15 -08001680
Wink Saville4dcab4f2012-11-19 16:05:13 -08001681 RLOGD("requesting data connection to APN '%s'", apn);
The Android Open Source Project00f06fc2009-03-03 19:32:15 -08001682
1683 fd = open ("/dev/qmi", O_RDWR);
1684 if (fd >= 0) { /* the device doesn't exist on the emulator */
1685
Wink Saville4dcab4f2012-11-19 16:05:13 -08001686 RLOGD("opened the qmi device\n");
Lorenzo Colitti4f81dcf2010-09-01 19:38:57 -07001687 asprintf(&cmd, "up:%s", apn);
1688 len = strlen(cmd);
The Android Open Source Project00f06fc2009-03-03 19:32:15 -08001689
Lorenzo Colitti4f81dcf2010-09-01 19:38:57 -07001690 while (cur < len) {
1691 do {
1692 written = write (fd, cmd + cur, len - cur);
1693 } while (written < 0 && errno == EINTR);
The Android Open Source Project00f06fc2009-03-03 19:32:15 -08001694
Lorenzo Colitti4f81dcf2010-09-01 19:38:57 -07001695 if (written < 0) {
Wink Saville4dcab4f2012-11-19 16:05:13 -08001696 RLOGE("### ERROR writing to /dev/qmi");
The Android Open Source Project00f06fc2009-03-03 19:32:15 -08001697 close(fd);
1698 goto error;
1699 }
1700
1701 cur += written;
1702 }
1703
1704 // wait for interface to come online
1705
1706 do {
1707 sleep(1);
1708 do {
1709 rlen = read(fd, status, 31);
1710 } while (rlen < 0 && errno == EINTR);
1711
1712 if (rlen < 0) {
Wink Saville4dcab4f2012-11-19 16:05:13 -08001713 RLOGE("### ERROR reading from /dev/qmi");
The Android Open Source Project00f06fc2009-03-03 19:32:15 -08001714 close(fd);
1715 goto error;
1716 } else {
1717 status[rlen] = '\0';
Wink Saville4dcab4f2012-11-19 16:05:13 -08001718 RLOGD("### status: %s", status);
The Android Open Source Project00f06fc2009-03-03 19:32:15 -08001719 }
1720 } while (strncmp(status, "STATE=up", 8) && strcmp(status, "online") && --retry);
1721
1722 close(fd);
1723
1724 if (retry == 0) {
Wink Saville4dcab4f2012-11-19 16:05:13 -08001725 RLOGE("### Failed to get data connection up\n");
Lorenzo Colitti4f81dcf2010-09-01 19:38:57 -07001726 goto error;
1727 }
The Android Open Source Project00f06fc2009-03-03 19:32:15 -08001728
1729 qmistatus = system("netcfg rmnet0 dhcp");
1730
Wink Saville4dcab4f2012-11-19 16:05:13 -08001731 RLOGD("netcfg rmnet0 dhcp: status %d\n", qmistatus);
The Android Open Source Project00f06fc2009-03-03 19:32:15 -08001732
Lorenzo Colitti4f81dcf2010-09-01 19:38:57 -07001733 if (qmistatus < 0) goto error;
The Android Open Source Project00f06fc2009-03-03 19:32:15 -08001734
Lorenzo Colitti4f81dcf2010-09-01 19:38:57 -07001735 } else {
The Android Open Source Project00f06fc2009-03-03 19:32:15 -08001736
Lorenzo Colitti4f81dcf2010-09-01 19:38:57 -07001737 if (datalen > 6 * sizeof(char *)) {
1738 pdp_type = ((const char **)data)[6];
1739 } else {
1740 pdp_type = "IP";
1741 }
The Android Open Source Project00f06fc2009-03-03 19:32:15 -08001742
David 'Digit' Turneraf1298d2011-02-04 13:36:47 +01001743 asprintf(&cmd, "AT+CGDCONT=1,\"%s\",\"%s\",,0,0", pdp_type, apn);
Lorenzo Colitti4f81dcf2010-09-01 19:38:57 -07001744 //FIXME check for error here
1745 err = at_send_command(cmd, NULL);
1746 free(cmd);
The Android Open Source Project00f06fc2009-03-03 19:32:15 -08001747
Lorenzo Colitti4f81dcf2010-09-01 19:38:57 -07001748 // Set required QoS params to default
1749 err = at_send_command("AT+CGQREQ=1", NULL);
The Android Open Source Project00f06fc2009-03-03 19:32:15 -08001750
Lorenzo Colitti4f81dcf2010-09-01 19:38:57 -07001751 // Set minimum QoS params to default
1752 err = at_send_command("AT+CGQMIN=1", NULL);
The Android Open Source Project00f06fc2009-03-03 19:32:15 -08001753
Lorenzo Colitti4f81dcf2010-09-01 19:38:57 -07001754 // packet-domain event reporting
1755 err = at_send_command("AT+CGEREP=1,0", NULL);
The Android Open Source Project00f06fc2009-03-03 19:32:15 -08001756
Lorenzo Colitti4f81dcf2010-09-01 19:38:57 -07001757 // Hangup anything that's happening there now
1758 err = at_send_command("AT+CGACT=1,0", NULL);
The Android Open Source Project00f06fc2009-03-03 19:32:15 -08001759
Lorenzo Colitti4f81dcf2010-09-01 19:38:57 -07001760 // Start data on PDP context 1
1761 err = at_send_command("ATD*99***1#", &p_response);
1762
1763 if (err < 0 || p_response->success == 0) {
1764 goto error;
1765 }
The Android Open Source Project00f06fc2009-03-03 19:32:15 -08001766 }
1767
Wink Saville43808972011-01-13 17:39:51 -08001768 requestOrSendDataCallList(&t);
1769
The Android Open Source Project00f06fc2009-03-03 19:32:15 -08001770 at_response_free(p_response);
1771
1772 return;
1773error:
1774 RIL_onRequestComplete(t, RIL_E_GENERIC_FAILURE, NULL, 0);
1775 at_response_free(p_response);
1776
1777}
1778
Mark Salyzynba58c202014-03-12 15:20:22 -07001779static void requestSMSAcknowledge(void *data, size_t datalen __unused, RIL_Token t)
The Android Open Source Project00f06fc2009-03-03 19:32:15 -08001780{
1781 int ackSuccess;
1782 int err;
1783
1784 ackSuccess = ((int *)data)[0];
1785
1786 if (ackSuccess == 1) {
1787 err = at_send_command("AT+CNMA=1", NULL);
1788 } else if (ackSuccess == 0) {
1789 err = at_send_command("AT+CNMA=2", NULL);
1790 } else {
Wink Saville4dcab4f2012-11-19 16:05:13 -08001791 RLOGE("unsupported arg to RIL_REQUEST_SMS_ACKNOWLEDGE\n");
The Android Open Source Project00f06fc2009-03-03 19:32:15 -08001792 goto error;
1793 }
1794
1795 RIL_onRequestComplete(t, RIL_E_SUCCESS, NULL, 0);
1796error:
1797 RIL_onRequestComplete(t, RIL_E_GENERIC_FAILURE, NULL, 0);
1798
1799}
1800
Mark Salyzynba58c202014-03-12 15:20:22 -07001801static void requestSIM_IO(void *data, size_t datalen __unused, RIL_Token t)
The Android Open Source Project00f06fc2009-03-03 19:32:15 -08001802{
1803 ATResponse *p_response = NULL;
1804 RIL_SIM_IO_Response sr;
1805 int err;
1806 char *cmd = NULL;
Wink Saville2c1fb3a2011-03-19 13:42:45 -07001807 RIL_SIM_IO_v6 *p_args;
The Android Open Source Project00f06fc2009-03-03 19:32:15 -08001808 char *line;
1809
1810 memset(&sr, 0, sizeof(sr));
1811
Wink Saville2c1fb3a2011-03-19 13:42:45 -07001812 p_args = (RIL_SIM_IO_v6 *)data;
The Android Open Source Project00f06fc2009-03-03 19:32:15 -08001813
1814 /* FIXME handle pin2 */
1815
1816 if (p_args->data == NULL) {
1817 asprintf(&cmd, "AT+CRSM=%d,%d,%d,%d,%d",
1818 p_args->command, p_args->fileid,
1819 p_args->p1, p_args->p2, p_args->p3);
1820 } else {
1821 asprintf(&cmd, "AT+CRSM=%d,%d,%d,%d,%d,%s",
1822 p_args->command, p_args->fileid,
1823 p_args->p1, p_args->p2, p_args->p3, p_args->data);
1824 }
1825
1826 err = at_send_command_singleline(cmd, "+CRSM:", &p_response);
1827
1828 if (err < 0 || p_response->success == 0) {
1829 goto error;
1830 }
1831
1832 line = p_response->p_intermediates->line;
1833
1834 err = at_tok_start(&line);
1835 if (err < 0) goto error;
1836
1837 err = at_tok_nextint(&line, &(sr.sw1));
1838 if (err < 0) goto error;
1839
1840 err = at_tok_nextint(&line, &(sr.sw2));
1841 if (err < 0) goto error;
1842
1843 if (at_tok_hasmore(&line)) {
1844 err = at_tok_nextstr(&line, &(sr.simResponse));
1845 if (err < 0) goto error;
1846 }
1847
1848 RIL_onRequestComplete(t, RIL_E_SUCCESS, &sr, sizeof(sr));
1849 at_response_free(p_response);
1850 free(cmd);
1851
1852 return;
1853error:
1854 RIL_onRequestComplete(t, RIL_E_GENERIC_FAILURE, NULL, 0);
1855 at_response_free(p_response);
1856 free(cmd);
1857
1858}
1859
1860static void requestEnterSimPin(void* data, size_t datalen, RIL_Token t)
1861{
1862 ATResponse *p_response = NULL;
1863 int err;
1864 char* cmd = NULL;
1865 const char** strings = (const char**)data;;
1866
1867 if ( datalen == sizeof(char*) ) {
1868 asprintf(&cmd, "AT+CPIN=%s", strings[0]);
1869 } else if ( datalen == 2*sizeof(char*) ) {
1870 asprintf(&cmd, "AT+CPIN=%s,%s", strings[0], strings[1]);
1871 } else
1872 goto error;
1873
1874 err = at_send_command_singleline(cmd, "+CPIN:", &p_response);
1875 free(cmd);
1876
1877 if (err < 0 || p_response->success == 0) {
1878error:
1879 RIL_onRequestComplete(t, RIL_E_PASSWORD_INCORRECT, NULL, 0);
1880 } else {
1881 RIL_onRequestComplete(t, RIL_E_SUCCESS, NULL, 0);
1882 }
1883 at_response_free(p_response);
1884}
1885
1886
Mark Salyzynba58c202014-03-12 15:20:22 -07001887static void requestSendUSSD(void *data, size_t datalen __unused, RIL_Token t)
The Android Open Source Project00f06fc2009-03-03 19:32:15 -08001888{
1889 const char *ussdRequest;
1890
1891 ussdRequest = (char *)(data);
1892
1893
1894 RIL_onRequestComplete(t, RIL_E_REQUEST_NOT_SUPPORTED, NULL, 0);
1895
1896// @@@ TODO
1897
1898}
1899
Mark Salyzynba58c202014-03-12 15:20:22 -07001900static void requestExitEmergencyMode(void *data __unused, size_t datalen __unused, RIL_Token t)
Jaime A Lopez-Sollanoe9645042012-08-29 07:27:27 -07001901{
1902 int err;
1903 ATResponse *p_response = NULL;
1904
1905 err = at_send_command("AT+WSOS=0", &p_response);
1906
1907 if (err < 0 || p_response->success == 0) {
1908 RIL_onRequestComplete(t, RIL_E_GENERIC_FAILURE, NULL, 0);
1909 return;
1910 }
1911
1912 RIL_onRequestComplete(t, RIL_E_SUCCESS, NULL, 0);
1913}
1914
1915// TODO: Use all radio types
1916static int techFromModemType(int mdmtype)
1917{
1918 int ret = -1;
1919 switch (1 << mdmtype) {
1920 case MDM_CDMA:
1921 ret = RADIO_TECH_1xRTT;
1922 break;
1923 case MDM_EVDO:
1924 ret = RADIO_TECH_EVDO_A;
1925 break;
1926 case MDM_GSM:
1927 ret = RADIO_TECH_GPRS;
1928 break;
1929 case MDM_WCDMA:
1930 ret = RADIO_TECH_HSPA;
1931 break;
1932 case MDM_LTE:
1933 ret = RADIO_TECH_LTE;
1934 break;
1935 }
1936 return ret;
1937}
The Android Open Source Project00f06fc2009-03-03 19:32:15 -08001938
Mark Salyzynba58c202014-03-12 15:20:22 -07001939static void requestGetCellInfoList(void *data __unused, size_t datalen __unused, RIL_Token t)
Wink Saville8a9e0212013-04-09 12:11:38 -07001940{
1941 uint64_t curTime = ril_nano_time();
1942 RIL_CellInfo ci[1] =
1943 {
1944 { // ci[0]
1945 1, // cellInfoType
1946 1, // registered
Sanket Padawef0c8ca72016-06-30 15:01:08 -07001947 RIL_TIMESTAMP_TYPE_MODEM,
Wink Saville8a9e0212013-04-09 12:11:38 -07001948 curTime - 1000, // Fake some time in the past
1949 { // union CellInfo
1950 { // RIL_CellInfoGsm gsm
1951 { // gsm.cellIdneityGsm
1952 s_mcc, // mcc
1953 s_mnc, // mnc
1954 s_lac, // lac
1955 s_cid, // cid
Wink Saville8a9e0212013-04-09 12:11:38 -07001956 },
1957 { // gsm.signalStrengthGsm
1958 10, // signalStrength
1959 0 // bitErrorRate
1960 }
1961 }
1962 }
1963 }
1964 };
1965
1966 RIL_onRequestComplete(t, RIL_E_SUCCESS, ci, sizeof(ci));
1967}
1968
1969
Sanket Padawef0c8ca72016-06-30 15:01:08 -07001970static void requestSetCellInfoListRate(void *data, size_t datalen __unused, RIL_Token t)
Wink Saville8a9e0212013-04-09 12:11:38 -07001971{
1972 // For now we'll save the rate but no RIL_UNSOL_CELL_INFO_LIST messages
1973 // will be sent.
1974 assert (datalen == sizeof(int));
1975 s_cell_info_rate_ms = ((int *)data)[0];
1976
1977 RIL_onRequestComplete(t, RIL_E_SUCCESS, NULL, 0);
1978}
1979
Etan Cohend3652192014-06-20 08:28:44 -07001980static void requestGetHardwareConfig(void *data, size_t datalen, RIL_Token t)
1981{
1982 // TODO - hook this up with real query/info from radio.
1983
1984 RIL_HardwareConfig hwCfg;
1985
1986 RIL_UNUSED_PARM(data);
1987 RIL_UNUSED_PARM(datalen);
1988
1989 hwCfg.type = -1;
1990
1991 RIL_onRequestComplete(t, RIL_E_SUCCESS, &hwCfg, sizeof(hwCfg));
1992}
1993
1994
The Android Open Source Project00f06fc2009-03-03 19:32:15 -08001995/*** Callback methods from the RIL library to us ***/
1996
1997/**
1998 * Call from RIL to us to make a RIL_REQUEST
1999 *
2000 * Must be completed with a call to RIL_onRequestComplete()
2001 *
2002 * RIL_onRequestComplete() may be called from any thread, before or after
2003 * this function returns.
2004 *
2005 * Will always be called from the same thread, so returning here implies
2006 * that the radio is ready to process another command (whether or not
2007 * the previous command has completed).
2008 */
2009static void
2010onRequest (int request, void *data, size_t datalen, RIL_Token t)
2011{
2012 ATResponse *p_response;
2013 int err;
2014
Wink Saville4dcab4f2012-11-19 16:05:13 -08002015 RLOGD("onRequest: %s", requestToString(request));
The Android Open Source Project00f06fc2009-03-03 19:32:15 -08002016
2017 /* Ignore all requests except RIL_REQUEST_GET_SIM_STATUS
2018 * when RADIO_STATE_UNAVAILABLE.
2019 */
2020 if (sState == RADIO_STATE_UNAVAILABLE
2021 && request != RIL_REQUEST_GET_SIM_STATUS
2022 ) {
2023 RIL_onRequestComplete(t, RIL_E_RADIO_NOT_AVAILABLE, NULL, 0);
2024 return;
2025 }
2026
2027 /* Ignore all non-power requests when RADIO_STATE_OFF
2028 * (except RIL_REQUEST_GET_SIM_STATUS)
2029 */
2030 if (sState == RADIO_STATE_OFF
2031 && !(request == RIL_REQUEST_RADIO_POWER
2032 || request == RIL_REQUEST_GET_SIM_STATUS)
2033 ) {
2034 RIL_onRequestComplete(t, RIL_E_RADIO_NOT_AVAILABLE, NULL, 0);
2035 return;
2036 }
2037
2038 switch (request) {
2039 case RIL_REQUEST_GET_SIM_STATUS: {
Wink Saville2c1fb3a2011-03-19 13:42:45 -07002040 RIL_CardStatus_v6 *p_card_status;
Wink Savillef6aa7c12009-04-30 14:20:52 -07002041 char *p_buffer;
2042 int buffer_size;
The Android Open Source Project00f06fc2009-03-03 19:32:15 -08002043
Wink Savillef6aa7c12009-04-30 14:20:52 -07002044 int result = getCardStatus(&p_card_status);
2045 if (result == RIL_E_SUCCESS) {
2046 p_buffer = (char *)p_card_status;
2047 buffer_size = sizeof(*p_card_status);
2048 } else {
2049 p_buffer = NULL;
2050 buffer_size = 0;
2051 }
2052 RIL_onRequestComplete(t, result, p_buffer, buffer_size);
2053 freeCardStatus(p_card_status);
The Android Open Source Project00f06fc2009-03-03 19:32:15 -08002054 break;
2055 }
2056 case RIL_REQUEST_GET_CURRENT_CALLS:
2057 requestGetCurrentCalls(data, datalen, t);
2058 break;
2059 case RIL_REQUEST_DIAL:
2060 requestDial(data, datalen, t);
2061 break;
2062 case RIL_REQUEST_HANGUP:
2063 requestHangup(data, datalen, t);
2064 break;
2065 case RIL_REQUEST_HANGUP_WAITING_OR_BACKGROUND:
2066 // 3GPP 22.030 6.5.5
2067 // "Releases all held calls or sets User Determined User Busy
2068 // (UDUB) for a waiting call."
2069 at_send_command("AT+CHLD=0", NULL);
2070
2071 /* success or failure is ignored by the upper layer here.
2072 it will call GET_CURRENT_CALLS and determine success that way */
2073 RIL_onRequestComplete(t, RIL_E_SUCCESS, NULL, 0);
2074 break;
2075 case RIL_REQUEST_HANGUP_FOREGROUND_RESUME_BACKGROUND:
2076 // 3GPP 22.030 6.5.5
2077 // "Releases all active calls (if any exist) and accepts
2078 // the other (held or waiting) call."
2079 at_send_command("AT+CHLD=1", NULL);
2080
2081 /* success or failure is ignored by the upper layer here.
2082 it will call GET_CURRENT_CALLS and determine success that way */
2083 RIL_onRequestComplete(t, RIL_E_SUCCESS, NULL, 0);
2084 break;
2085 case RIL_REQUEST_SWITCH_WAITING_OR_HOLDING_AND_ACTIVE:
2086 // 3GPP 22.030 6.5.5
2087 // "Places all active calls (if any exist) on hold and accepts
2088 // the other (held or waiting) call."
2089 at_send_command("AT+CHLD=2", NULL);
2090
2091#ifdef WORKAROUND_ERRONEOUS_ANSWER
2092 s_expectAnswer = 1;
2093#endif /* WORKAROUND_ERRONEOUS_ANSWER */
2094
2095 /* success or failure is ignored by the upper layer here.
2096 it will call GET_CURRENT_CALLS and determine success that way */
2097 RIL_onRequestComplete(t, RIL_E_SUCCESS, NULL, 0);
2098 break;
2099 case RIL_REQUEST_ANSWER:
2100 at_send_command("ATA", NULL);
2101
2102#ifdef WORKAROUND_ERRONEOUS_ANSWER
2103 s_expectAnswer = 1;
2104#endif /* WORKAROUND_ERRONEOUS_ANSWER */
2105
2106 /* success or failure is ignored by the upper layer here.
2107 it will call GET_CURRENT_CALLS and determine success that way */
2108 RIL_onRequestComplete(t, RIL_E_SUCCESS, NULL, 0);
2109 break;
2110 case RIL_REQUEST_CONFERENCE:
2111 // 3GPP 22.030 6.5.5
2112 // "Adds a held call to the conversation"
2113 at_send_command("AT+CHLD=3", NULL);
2114
2115 /* success or failure is ignored by the upper layer here.
2116 it will call GET_CURRENT_CALLS and determine success that way */
2117 RIL_onRequestComplete(t, RIL_E_SUCCESS, NULL, 0);
2118 break;
2119 case RIL_REQUEST_UDUB:
2120 /* user determined user busy */
2121 /* sometimes used: ATH */
2122 at_send_command("ATH", NULL);
2123
2124 /* success or failure is ignored by the upper layer here.
2125 it will call GET_CURRENT_CALLS and determine success that way */
2126 RIL_onRequestComplete(t, RIL_E_SUCCESS, NULL, 0);
2127 break;
2128
2129 case RIL_REQUEST_SEPARATE_CONNECTION:
2130 {
2131 char cmd[12];
2132 int party = ((int*)data)[0];
2133
2134 // Make sure that party is in a valid range.
2135 // (Note: The Telephony middle layer imposes a range of 1 to 7.
2136 // It's sufficient for us to just make sure it's single digit.)
2137 if (party > 0 && party < 10) {
2138 sprintf(cmd, "AT+CHLD=2%d", party);
2139 at_send_command(cmd, NULL);
2140 RIL_onRequestComplete(t, RIL_E_SUCCESS, NULL, 0);
2141 } else {
2142 RIL_onRequestComplete(t, RIL_E_GENERIC_FAILURE, NULL, 0);
2143 }
2144 }
2145 break;
2146
2147 case RIL_REQUEST_SIGNAL_STRENGTH:
2148 requestSignalStrength(data, datalen, t);
2149 break;
Wink Saville2c1fb3a2011-03-19 13:42:45 -07002150 case RIL_REQUEST_VOICE_REGISTRATION_STATE:
2151 case RIL_REQUEST_DATA_REGISTRATION_STATE:
The Android Open Source Project00f06fc2009-03-03 19:32:15 -08002152 requestRegistrationState(request, data, datalen, t);
2153 break;
2154 case RIL_REQUEST_OPERATOR:
2155 requestOperator(data, datalen, t);
2156 break;
2157 case RIL_REQUEST_RADIO_POWER:
2158 requestRadioPower(data, datalen, t);
2159 break;
2160 case RIL_REQUEST_DTMF: {
2161 char c = ((char *)data)[0];
2162 char *cmd;
2163 asprintf(&cmd, "AT+VTS=%c", (int)c);
2164 at_send_command(cmd, NULL);
2165 free(cmd);
2166 RIL_onRequestComplete(t, RIL_E_SUCCESS, NULL, 0);
2167 break;
2168 }
2169 case RIL_REQUEST_SEND_SMS:
Chaitanya Saggurthi33bbe432013-09-24 16:16:21 +05302170 case RIL_REQUEST_SEND_SMS_EXPECT_MORE:
The Android Open Source Project00f06fc2009-03-03 19:32:15 -08002171 requestSendSMS(data, datalen, t);
2172 break;
Jaime A Lopez-Sollanoe9645042012-08-29 07:27:27 -07002173 case RIL_REQUEST_CDMA_SEND_SMS:
2174 requestCdmaSendSMS(data, datalen, t);
2175 break;
Sukanya Rajkhowaa18b9d12013-09-10 12:30:13 -07002176 case RIL_REQUEST_IMS_SEND_SMS:
2177 requestImsSendSMS(data, datalen, t);
2178 break;
Wink Savillef4c4d362009-04-02 01:37:03 -07002179 case RIL_REQUEST_SETUP_DATA_CALL:
2180 requestSetupDataCall(data, datalen, t);
The Android Open Source Project00f06fc2009-03-03 19:32:15 -08002181 break;
2182 case RIL_REQUEST_SMS_ACKNOWLEDGE:
2183 requestSMSAcknowledge(data, datalen, t);
2184 break;
2185
2186 case RIL_REQUEST_GET_IMSI:
2187 p_response = NULL;
2188 err = at_send_command_numeric("AT+CIMI", &p_response);
2189
2190 if (err < 0 || p_response->success == 0) {
2191 RIL_onRequestComplete(t, RIL_E_GENERIC_FAILURE, NULL, 0);
2192 } else {
2193 RIL_onRequestComplete(t, RIL_E_SUCCESS,
2194 p_response->p_intermediates->line, sizeof(char *));
2195 }
2196 at_response_free(p_response);
2197 break;
2198
2199 case RIL_REQUEST_GET_IMEI:
2200 p_response = NULL;
2201 err = at_send_command_numeric("AT+CGSN", &p_response);
2202
2203 if (err < 0 || p_response->success == 0) {
2204 RIL_onRequestComplete(t, RIL_E_GENERIC_FAILURE, NULL, 0);
2205 } else {
2206 RIL_onRequestComplete(t, RIL_E_SUCCESS,
2207 p_response->p_intermediates->line, sizeof(char *));
2208 }
2209 at_response_free(p_response);
2210 break;
2211
2212 case RIL_REQUEST_SIM_IO:
2213 requestSIM_IO(data,datalen,t);
2214 break;
2215
2216 case RIL_REQUEST_SEND_USSD:
2217 requestSendUSSD(data, datalen, t);
2218 break;
2219
2220 case RIL_REQUEST_CANCEL_USSD:
2221 p_response = NULL;
2222 err = at_send_command_numeric("AT+CUSD=2", &p_response);
2223
2224 if (err < 0 || p_response->success == 0) {
2225 RIL_onRequestComplete(t, RIL_E_GENERIC_FAILURE, NULL, 0);
2226 } else {
2227 RIL_onRequestComplete(t, RIL_E_SUCCESS,
2228 p_response->p_intermediates->line, sizeof(char *));
2229 }
2230 at_response_free(p_response);
2231 break;
2232
2233 case RIL_REQUEST_SET_NETWORK_SELECTION_AUTOMATIC:
2234 at_send_command("AT+COPS=0", NULL);
2235 break;
2236
Wink Savillef4c4d362009-04-02 01:37:03 -07002237 case RIL_REQUEST_DATA_CALL_LIST:
2238 requestDataCallList(data, datalen, t);
The Android Open Source Project00f06fc2009-03-03 19:32:15 -08002239 break;
2240
2241 case RIL_REQUEST_QUERY_NETWORK_SELECTION_MODE:
2242 requestQueryNetworkSelectionMode(data, datalen, t);
2243 break;
2244
2245 case RIL_REQUEST_OEM_HOOK_RAW:
2246 // echo back data
2247 RIL_onRequestComplete(t, RIL_E_SUCCESS, data, datalen);
2248 break;
2249
2250
2251 case RIL_REQUEST_OEM_HOOK_STRINGS: {
2252 int i;
2253 const char ** cur;
2254
Wink Saville4dcab4f2012-11-19 16:05:13 -08002255 RLOGD("got OEM_HOOK_STRINGS: 0x%8p %lu", data, (long)datalen);
The Android Open Source Project00f06fc2009-03-03 19:32:15 -08002256
2257
2258 for (i = (datalen / sizeof (char *)), cur = (const char **)data ;
2259 i > 0 ; cur++, i --) {
Wink Saville4dcab4f2012-11-19 16:05:13 -08002260 RLOGD("> '%s'", *cur);
The Android Open Source Project00f06fc2009-03-03 19:32:15 -08002261 }
2262
2263 // echo back strings
2264 RIL_onRequestComplete(t, RIL_E_SUCCESS, data, datalen);
2265 break;
2266 }
2267
2268 case RIL_REQUEST_WRITE_SMS_TO_SIM:
2269 requestWriteSmsToSim(data, datalen, t);
2270 break;
2271
2272 case RIL_REQUEST_DELETE_SMS_ON_SIM: {
2273 char * cmd;
2274 p_response = NULL;
2275 asprintf(&cmd, "AT+CMGD=%d", ((int *)data)[0]);
2276 err = at_send_command(cmd, &p_response);
2277 free(cmd);
2278 if (err < 0 || p_response->success == 0) {
2279 RIL_onRequestComplete(t, RIL_E_GENERIC_FAILURE, NULL, 0);
2280 } else {
2281 RIL_onRequestComplete(t, RIL_E_SUCCESS, NULL, 0);
2282 }
2283 at_response_free(p_response);
2284 break;
2285 }
2286
2287 case RIL_REQUEST_ENTER_SIM_PIN:
2288 case RIL_REQUEST_ENTER_SIM_PUK:
2289 case RIL_REQUEST_ENTER_SIM_PIN2:
2290 case RIL_REQUEST_ENTER_SIM_PUK2:
2291 case RIL_REQUEST_CHANGE_SIM_PIN:
2292 case RIL_REQUEST_CHANGE_SIM_PIN2:
2293 requestEnterSimPin(data, datalen, t);
2294 break;
2295
Sukanya Rajkhowaa18b9d12013-09-10 12:30:13 -07002296 case RIL_REQUEST_IMS_REGISTRATION_STATE: {
2297 int reply[2];
2298 //0==unregistered, 1==registered
2299 reply[0] = s_ims_registered;
2300
2301 //to be used when changed to include service supporated info
2302 //reply[1] = s_ims_services;
2303
2304 // FORMAT_3GPP(1) vs FORMAT_3GPP2(2);
2305 reply[1] = s_ims_format;
2306
2307 RLOGD("IMS_REGISTRATION=%d, format=%d ",
2308 reply[0], reply[1]);
2309 if (reply[1] != -1) {
2310 RIL_onRequestComplete(t, RIL_E_SUCCESS, reply, sizeof(reply));
2311 } else {
2312 RIL_onRequestComplete(t, RIL_E_GENERIC_FAILURE, NULL, 0);
2313 }
2314 break;
2315 }
2316
Jaime A Lopez-Sollanoe9645042012-08-29 07:27:27 -07002317 case RIL_REQUEST_VOICE_RADIO_TECH:
2318 {
2319 int tech = techFromModemType(TECH(sMdmInfo));
2320 if (tech < 0 )
2321 RIL_onRequestComplete(t, RIL_E_GENERIC_FAILURE, NULL, 0);
2322 else
2323 RIL_onRequestComplete(t, RIL_E_SUCCESS, &tech, sizeof(tech));
2324 }
2325 break;
2326 case RIL_REQUEST_SET_PREFERRED_NETWORK_TYPE:
2327 requestSetPreferredNetworkType(request, data, datalen, t);
2328 break;
2329
2330 case RIL_REQUEST_GET_PREFERRED_NETWORK_TYPE:
2331 requestGetPreferredNetworkType(request, data, datalen, t);
2332 break;
2333
Jun Tian58027012013-07-30 11:07:22 +08002334 case RIL_REQUEST_GET_CELL_INFO_LIST:
2335 requestGetCellInfoList(data, datalen, t);
2336 break;
2337
2338 case RIL_REQUEST_SET_UNSOL_CELL_INFO_LIST_RATE:
2339 requestSetCellInfoListRate(data, datalen, t);
2340 break;
2341
Etan Cohend3652192014-06-20 08:28:44 -07002342 case RIL_REQUEST_GET_HARDWARE_CONFIG:
2343 requestGetHardwareConfig(data, datalen, t);
2344 break;
2345
Naveen Kallaa65a16a2014-07-31 16:48:31 -07002346 case RIL_REQUEST_SHUTDOWN:
2347 requestShutdown(t);
2348 break;
2349
Jaime A Lopez-Sollanoe9645042012-08-29 07:27:27 -07002350 /* CDMA Specific Requests */
2351 case RIL_REQUEST_BASEBAND_VERSION:
2352 if (TECH_BIT(sMdmInfo) == MDM_CDMA) {
2353 requestCdmaBaseBandVersion(request, data, datalen, t);
2354 break;
2355 } // Fall-through if tech is not cdma
2356
2357 case RIL_REQUEST_DEVICE_IDENTITY:
2358 if (TECH_BIT(sMdmInfo) == MDM_CDMA) {
2359 requestCdmaDeviceIdentity(request, data, datalen, t);
2360 break;
2361 } // Fall-through if tech is not cdma
2362
2363 case RIL_REQUEST_CDMA_SUBSCRIPTION:
2364 if (TECH_BIT(sMdmInfo) == MDM_CDMA) {
2365 requestCdmaSubscription(request, data, datalen, t);
2366 break;
2367 } // Fall-through if tech is not cdma
2368
2369 case RIL_REQUEST_CDMA_SET_SUBSCRIPTION_SOURCE:
2370 if (TECH_BIT(sMdmInfo) == MDM_CDMA) {
2371 requestCdmaSetSubscriptionSource(request, data, datalen, t);
2372 break;
2373 } // Fall-through if tech is not cdma
2374
2375 case RIL_REQUEST_CDMA_GET_SUBSCRIPTION_SOURCE:
2376 if (TECH_BIT(sMdmInfo) == MDM_CDMA) {
2377 requestCdmaGetSubscriptionSource(request, data, datalen, t);
2378 break;
2379 } // Fall-through if tech is not cdma
2380
2381 case RIL_REQUEST_CDMA_QUERY_ROAMING_PREFERENCE:
2382 if (TECH_BIT(sMdmInfo) == MDM_CDMA) {
2383 requestCdmaGetRoamingPreference(request, data, datalen, t);
2384 break;
2385 } // Fall-through if tech is not cdma
2386
2387 case RIL_REQUEST_CDMA_SET_ROAMING_PREFERENCE:
2388 if (TECH_BIT(sMdmInfo) == MDM_CDMA) {
2389 requestCdmaSetRoamingPreference(request, data, datalen, t);
2390 break;
2391 } // Fall-through if tech is not cdma
2392
2393 case RIL_REQUEST_EXIT_EMERGENCY_CALLBACK_MODE:
2394 if (TECH_BIT(sMdmInfo) == MDM_CDMA) {
2395 requestExitEmergencyMode(data, datalen, t);
2396 break;
2397 } // Fall-through if tech is not cdma
2398
The Android Open Source Project00f06fc2009-03-03 19:32:15 -08002399 default:
Wink Saville4dcab4f2012-11-19 16:05:13 -08002400 RLOGD("Request not supported. Tech: %d",TECH(sMdmInfo));
The Android Open Source Project00f06fc2009-03-03 19:32:15 -08002401 RIL_onRequestComplete(t, RIL_E_REQUEST_NOT_SUPPORTED, NULL, 0);
2402 break;
2403 }
2404}
2405
2406/**
2407 * Synchronous call from the RIL to us to return current radio state.
2408 * RADIO_STATE_UNAVAILABLE should be the initial state.
2409 */
2410static RIL_RadioState
2411currentState()
2412{
2413 return sState;
2414}
2415/**
2416 * Call from RIL to us to find out whether a specific request code
2417 * is supported by this implementation.
2418 *
2419 * Return 1 for "supported" and 0 for "unsupported"
2420 */
2421
2422static int
Mark Salyzynba58c202014-03-12 15:20:22 -07002423onSupports (int requestCode __unused)
The Android Open Source Project00f06fc2009-03-03 19:32:15 -08002424{
2425 //@@@ todo
2426
2427 return 1;
2428}
2429
Mark Salyzynba58c202014-03-12 15:20:22 -07002430static void onCancel (RIL_Token t __unused)
The Android Open Source Project00f06fc2009-03-03 19:32:15 -08002431{
2432 //@@@todo
2433
2434}
2435
2436static const char * getVersion(void)
2437{
2438 return "android reference-ril 1.0";
2439}
2440
2441static void
Jaime A Lopez-Sollanoe9645042012-08-29 07:27:27 -07002442setRadioTechnology(ModemInfo *mdm, int newtech)
2443{
Wink Saville4dcab4f2012-11-19 16:05:13 -08002444 RLOGD("setRadioTechnology(%d)", newtech);
Jaime A Lopez-Sollanoe9645042012-08-29 07:27:27 -07002445
2446 int oldtech = TECH(mdm);
2447
2448 if (newtech != oldtech) {
Wink Saville4dcab4f2012-11-19 16:05:13 -08002449 RLOGD("Tech change (%d => %d)", oldtech, newtech);
Jaime A Lopez-Sollanoe9645042012-08-29 07:27:27 -07002450 TECH(mdm) = newtech;
2451 if (techFromModemType(newtech) != techFromModemType(oldtech)) {
2452 int tech = techFromModemType(TECH(sMdmInfo));
2453 if (tech > 0 ) {
2454 RIL_onUnsolicitedResponse(RIL_UNSOL_VOICE_RADIO_TECH_CHANGED,
2455 &tech, sizeof(tech));
2456 }
2457 }
2458 }
2459}
2460
2461static void
The Android Open Source Project00f06fc2009-03-03 19:32:15 -08002462setRadioState(RIL_RadioState newState)
2463{
Wink Saville4dcab4f2012-11-19 16:05:13 -08002464 RLOGD("setRadioState(%d)", newState);
The Android Open Source Project00f06fc2009-03-03 19:32:15 -08002465 RIL_RadioState oldState;
2466
2467 pthread_mutex_lock(&s_state_mutex);
2468
2469 oldState = sState;
2470
2471 if (s_closed > 0) {
2472 // If we're closed, the only reasonable state is
2473 // RADIO_STATE_UNAVAILABLE
2474 // This is here because things on the main thread
2475 // may attempt to change the radio state after the closed
2476 // event happened in another thread
2477 newState = RADIO_STATE_UNAVAILABLE;
2478 }
2479
2480 if (sState != newState || s_closed > 0) {
2481 sState = newState;
2482
2483 pthread_cond_broadcast (&s_state_cond);
2484 }
2485
2486 pthread_mutex_unlock(&s_state_mutex);
2487
2488
2489 /* do these outside of the mutex */
2490 if (sState != oldState) {
2491 RIL_onUnsolicitedResponse (RIL_UNSOL_RESPONSE_RADIO_STATE_CHANGED,
2492 NULL, 0);
Alex Yakavenka81d14852013-12-04 13:54:37 -08002493 // Sim state can change as result of radio state change
2494 RIL_onUnsolicitedResponse (RIL_UNSOL_RESPONSE_SIM_STATUS_CHANGED,
2495 NULL, 0);
The Android Open Source Project00f06fc2009-03-03 19:32:15 -08002496
2497 /* FIXME onSimReady() and onRadioPowerOn() cannot be called
2498 * from the AT reader thread
2499 * Currently, this doesn't happen, but if that changes then these
2500 * will need to be dispatched on the request thread
2501 */
Jaime A Lopez-Sollanoe9645042012-08-29 07:27:27 -07002502 if (sState == RADIO_STATE_ON) {
The Android Open Source Project00f06fc2009-03-03 19:32:15 -08002503 onRadioPowerOn();
2504 }
2505 }
2506}
2507
Jaime A Lopez-Sollanoe9645042012-08-29 07:27:27 -07002508/** Returns RUIM_NOT_READY on error */
2509static SIM_Status
2510getRUIMStatus()
2511{
2512 ATResponse *p_response = NULL;
2513 int err;
2514 int ret;
2515 char *cpinLine;
2516 char *cpinResult;
2517
2518 if (sState == RADIO_STATE_OFF || sState == RADIO_STATE_UNAVAILABLE) {
2519 ret = SIM_NOT_READY;
2520 goto done;
2521 }
2522
2523 err = at_send_command_singleline("AT+CPIN?", "+CPIN:", &p_response);
2524
2525 if (err != 0) {
2526 ret = SIM_NOT_READY;
2527 goto done;
2528 }
2529
2530 switch (at_get_cme_error(p_response)) {
2531 case CME_SUCCESS:
2532 break;
2533
2534 case CME_SIM_NOT_INSERTED:
2535 ret = SIM_ABSENT;
2536 goto done;
2537
2538 default:
2539 ret = SIM_NOT_READY;
2540 goto done;
2541 }
2542
2543 /* CPIN? has succeeded, now look at the result */
2544
2545 cpinLine = p_response->p_intermediates->line;
2546 err = at_tok_start (&cpinLine);
2547
2548 if (err < 0) {
2549 ret = SIM_NOT_READY;
2550 goto done;
2551 }
2552
2553 err = at_tok_nextstr(&cpinLine, &cpinResult);
2554
2555 if (err < 0) {
2556 ret = SIM_NOT_READY;
2557 goto done;
2558 }
2559
2560 if (0 == strcmp (cpinResult, "SIM PIN")) {
2561 ret = SIM_PIN;
2562 goto done;
2563 } else if (0 == strcmp (cpinResult, "SIM PUK")) {
2564 ret = SIM_PUK;
2565 goto done;
2566 } else if (0 == strcmp (cpinResult, "PH-NET PIN")) {
2567 return SIM_NETWORK_PERSONALIZATION;
2568 } else if (0 != strcmp (cpinResult, "READY")) {
2569 /* we're treating unsupported lock types as "sim absent" */
2570 ret = SIM_ABSENT;
2571 goto done;
2572 }
2573
2574 at_response_free(p_response);
2575 p_response = NULL;
2576 cpinResult = NULL;
2577
2578 ret = SIM_READY;
2579
2580done:
2581 at_response_free(p_response);
2582 return ret;
2583}
2584
John Wang309ac292009-07-30 14:53:23 -07002585/** Returns SIM_NOT_READY on error */
David 'Digit' Turneraf1298d2011-02-04 13:36:47 +01002586static SIM_Status
The Android Open Source Project00f06fc2009-03-03 19:32:15 -08002587getSIMStatus()
2588{
2589 ATResponse *p_response = NULL;
2590 int err;
2591 int ret;
2592 char *cpinLine;
2593 char *cpinResult;
2594
Wink Saville4dcab4f2012-11-19 16:05:13 -08002595 RLOGD("getSIMStatus(). sState: %d",sState);
The Android Open Source Project00f06fc2009-03-03 19:32:15 -08002596 if (sState == RADIO_STATE_OFF || sState == RADIO_STATE_UNAVAILABLE) {
John Wang309ac292009-07-30 14:53:23 -07002597 ret = SIM_NOT_READY;
The Android Open Source Project00f06fc2009-03-03 19:32:15 -08002598 goto done;
2599 }
2600
2601 err = at_send_command_singleline("AT+CPIN?", "+CPIN:", &p_response);
2602
2603 if (err != 0) {
John Wang309ac292009-07-30 14:53:23 -07002604 ret = SIM_NOT_READY;
The Android Open Source Project00f06fc2009-03-03 19:32:15 -08002605 goto done;
2606 }
2607
2608 switch (at_get_cme_error(p_response)) {
2609 case CME_SUCCESS:
2610 break;
2611
2612 case CME_SIM_NOT_INSERTED:
John Wang309ac292009-07-30 14:53:23 -07002613 ret = SIM_ABSENT;
The Android Open Source Project00f06fc2009-03-03 19:32:15 -08002614 goto done;
2615
2616 default:
John Wang309ac292009-07-30 14:53:23 -07002617 ret = SIM_NOT_READY;
The Android Open Source Project00f06fc2009-03-03 19:32:15 -08002618 goto done;
2619 }
2620
2621 /* CPIN? has succeeded, now look at the result */
2622
2623 cpinLine = p_response->p_intermediates->line;
2624 err = at_tok_start (&cpinLine);
2625
2626 if (err < 0) {
John Wang309ac292009-07-30 14:53:23 -07002627 ret = SIM_NOT_READY;
The Android Open Source Project00f06fc2009-03-03 19:32:15 -08002628 goto done;
2629 }
2630
2631 err = at_tok_nextstr(&cpinLine, &cpinResult);
2632
2633 if (err < 0) {
John Wang309ac292009-07-30 14:53:23 -07002634 ret = SIM_NOT_READY;
The Android Open Source Project00f06fc2009-03-03 19:32:15 -08002635 goto done;
2636 }
2637
2638 if (0 == strcmp (cpinResult, "SIM PIN")) {
John Wang309ac292009-07-30 14:53:23 -07002639 ret = SIM_PIN;
The Android Open Source Project00f06fc2009-03-03 19:32:15 -08002640 goto done;
2641 } else if (0 == strcmp (cpinResult, "SIM PUK")) {
John Wang309ac292009-07-30 14:53:23 -07002642 ret = SIM_PUK;
The Android Open Source Project00f06fc2009-03-03 19:32:15 -08002643 goto done;
2644 } else if (0 == strcmp (cpinResult, "PH-NET PIN")) {
John Wang309ac292009-07-30 14:53:23 -07002645 return SIM_NETWORK_PERSONALIZATION;
The Android Open Source Project00f06fc2009-03-03 19:32:15 -08002646 } else if (0 != strcmp (cpinResult, "READY")) {
2647 /* we're treating unsupported lock types as "sim absent" */
John Wang309ac292009-07-30 14:53:23 -07002648 ret = SIM_ABSENT;
The Android Open Source Project00f06fc2009-03-03 19:32:15 -08002649 goto done;
2650 }
2651
2652 at_response_free(p_response);
2653 p_response = NULL;
2654 cpinResult = NULL;
2655
John Wang309ac292009-07-30 14:53:23 -07002656 ret = SIM_READY;
The Android Open Source Project00f06fc2009-03-03 19:32:15 -08002657
2658done:
2659 at_response_free(p_response);
2660 return ret;
2661}
2662
2663
2664/**
Wink Savillef6aa7c12009-04-30 14:20:52 -07002665 * Get the current card status.
2666 *
2667 * This must be freed using freeCardStatus.
2668 * @return: On success returns RIL_E_SUCCESS
2669 */
Wink Saville2c1fb3a2011-03-19 13:42:45 -07002670static int getCardStatus(RIL_CardStatus_v6 **pp_card_status) {
Wink Savillef6aa7c12009-04-30 14:20:52 -07002671 static RIL_AppStatus app_status_array[] = {
John Wang309ac292009-07-30 14:53:23 -07002672 // SIM_ABSENT = 0
Wink Savillef6aa7c12009-04-30 14:20:52 -07002673 { RIL_APPTYPE_UNKNOWN, RIL_APPSTATE_UNKNOWN, RIL_PERSOSUBSTATE_UNKNOWN,
2674 NULL, NULL, 0, RIL_PINSTATE_UNKNOWN, RIL_PINSTATE_UNKNOWN },
John Wang309ac292009-07-30 14:53:23 -07002675 // SIM_NOT_READY = 1
Wink Savillef6aa7c12009-04-30 14:20:52 -07002676 { RIL_APPTYPE_SIM, RIL_APPSTATE_DETECTED, RIL_PERSOSUBSTATE_UNKNOWN,
2677 NULL, NULL, 0, RIL_PINSTATE_UNKNOWN, RIL_PINSTATE_UNKNOWN },
John Wang309ac292009-07-30 14:53:23 -07002678 // SIM_READY = 2
Wink Savillef6aa7c12009-04-30 14:20:52 -07002679 { RIL_APPTYPE_SIM, RIL_APPSTATE_READY, RIL_PERSOSUBSTATE_READY,
2680 NULL, NULL, 0, RIL_PINSTATE_UNKNOWN, RIL_PINSTATE_UNKNOWN },
John Wang309ac292009-07-30 14:53:23 -07002681 // SIM_PIN = 3
Wink Savillef6aa7c12009-04-30 14:20:52 -07002682 { RIL_APPTYPE_SIM, RIL_APPSTATE_PIN, RIL_PERSOSUBSTATE_UNKNOWN,
2683 NULL, NULL, 0, RIL_PINSTATE_ENABLED_NOT_VERIFIED, RIL_PINSTATE_UNKNOWN },
John Wang309ac292009-07-30 14:53:23 -07002684 // SIM_PUK = 4
Wink Savillef6aa7c12009-04-30 14:20:52 -07002685 { RIL_APPTYPE_SIM, RIL_APPSTATE_PUK, RIL_PERSOSUBSTATE_UNKNOWN,
2686 NULL, NULL, 0, RIL_PINSTATE_ENABLED_BLOCKED, RIL_PINSTATE_UNKNOWN },
John Wang309ac292009-07-30 14:53:23 -07002687 // SIM_NETWORK_PERSONALIZATION = 5
Wink Savillef6aa7c12009-04-30 14:20:52 -07002688 { RIL_APPTYPE_SIM, RIL_APPSTATE_SUBSCRIPTION_PERSO, RIL_PERSOSUBSTATE_SIM_NETWORK,
Jaime A Lopez-Sollanoe9645042012-08-29 07:27:27 -07002689 NULL, NULL, 0, RIL_PINSTATE_ENABLED_NOT_VERIFIED, RIL_PINSTATE_UNKNOWN },
2690 // RUIM_ABSENT = 6
2691 { RIL_APPTYPE_UNKNOWN, RIL_APPSTATE_UNKNOWN, RIL_PERSOSUBSTATE_UNKNOWN,
2692 NULL, NULL, 0, RIL_PINSTATE_UNKNOWN, RIL_PINSTATE_UNKNOWN },
2693 // RUIM_NOT_READY = 7
2694 { RIL_APPTYPE_RUIM, RIL_APPSTATE_DETECTED, RIL_PERSOSUBSTATE_UNKNOWN,
2695 NULL, NULL, 0, RIL_PINSTATE_UNKNOWN, RIL_PINSTATE_UNKNOWN },
2696 // RUIM_READY = 8
2697 { RIL_APPTYPE_RUIM, RIL_APPSTATE_READY, RIL_PERSOSUBSTATE_READY,
2698 NULL, NULL, 0, RIL_PINSTATE_UNKNOWN, RIL_PINSTATE_UNKNOWN },
2699 // RUIM_PIN = 9
2700 { RIL_APPTYPE_RUIM, RIL_APPSTATE_PIN, RIL_PERSOSUBSTATE_UNKNOWN,
2701 NULL, NULL, 0, RIL_PINSTATE_ENABLED_NOT_VERIFIED, RIL_PINSTATE_UNKNOWN },
2702 // RUIM_PUK = 10
2703 { RIL_APPTYPE_RUIM, RIL_APPSTATE_PUK, RIL_PERSOSUBSTATE_UNKNOWN,
2704 NULL, NULL, 0, RIL_PINSTATE_ENABLED_BLOCKED, RIL_PINSTATE_UNKNOWN },
2705 // RUIM_NETWORK_PERSONALIZATION = 11
2706 { RIL_APPTYPE_RUIM, RIL_APPSTATE_SUBSCRIPTION_PERSO, RIL_PERSOSUBSTATE_SIM_NETWORK,
2707 NULL, NULL, 0, RIL_PINSTATE_ENABLED_NOT_VERIFIED, RIL_PINSTATE_UNKNOWN }
Wink Savillef6aa7c12009-04-30 14:20:52 -07002708 };
2709 RIL_CardState card_state;
2710 int num_apps;
2711
2712 int sim_status = getSIMStatus();
John Wang309ac292009-07-30 14:53:23 -07002713 if (sim_status == SIM_ABSENT) {
Wink Savillef6aa7c12009-04-30 14:20:52 -07002714 card_state = RIL_CARDSTATE_ABSENT;
2715 num_apps = 0;
2716 } else {
2717 card_state = RIL_CARDSTATE_PRESENT;
Jaime A Lopez-Sollanoe9645042012-08-29 07:27:27 -07002718 num_apps = 2;
Wink Savillef6aa7c12009-04-30 14:20:52 -07002719 }
2720
2721 // Allocate and initialize base card status.
Wink Saville2c1fb3a2011-03-19 13:42:45 -07002722 RIL_CardStatus_v6 *p_card_status = malloc(sizeof(RIL_CardStatus_v6));
Wink Savillef6aa7c12009-04-30 14:20:52 -07002723 p_card_status->card_state = card_state;
2724 p_card_status->universal_pin_state = RIL_PINSTATE_UNKNOWN;
2725 p_card_status->gsm_umts_subscription_app_index = RIL_CARD_MAX_APPS;
2726 p_card_status->cdma_subscription_app_index = RIL_CARD_MAX_APPS;
Wink Saville2c1fb3a2011-03-19 13:42:45 -07002727 p_card_status->ims_subscription_app_index = RIL_CARD_MAX_APPS;
Wink Savillef6aa7c12009-04-30 14:20:52 -07002728 p_card_status->num_applications = num_apps;
2729
2730 // Initialize application status
2731 int i;
2732 for (i = 0; i < RIL_CARD_MAX_APPS; i++) {
John Wang309ac292009-07-30 14:53:23 -07002733 p_card_status->applications[i] = app_status_array[SIM_ABSENT];
Wink Savillef6aa7c12009-04-30 14:20:52 -07002734 }
2735
2736 // Pickup the appropriate application status
2737 // that reflects sim_status for gsm.
2738 if (num_apps != 0) {
2739 // Only support one app, gsm
Jaime A Lopez-Sollanoe9645042012-08-29 07:27:27 -07002740 p_card_status->num_applications = 2;
Wink Savillef6aa7c12009-04-30 14:20:52 -07002741 p_card_status->gsm_umts_subscription_app_index = 0;
Jaime A Lopez-Sollanoe9645042012-08-29 07:27:27 -07002742 p_card_status->cdma_subscription_app_index = 1;
Wink Savillef6aa7c12009-04-30 14:20:52 -07002743
2744 // Get the correct app status
2745 p_card_status->applications[0] = app_status_array[sim_status];
Jaime A Lopez-Sollanoe9645042012-08-29 07:27:27 -07002746 p_card_status->applications[1] = app_status_array[sim_status + RUIM_ABSENT];
Wink Savillef6aa7c12009-04-30 14:20:52 -07002747 }
2748
2749 *pp_card_status = p_card_status;
2750 return RIL_E_SUCCESS;
2751}
2752
2753/**
2754 * Free the card status returned by getCardStatus
2755 */
Wink Saville2c1fb3a2011-03-19 13:42:45 -07002756static void freeCardStatus(RIL_CardStatus_v6 *p_card_status) {
Wink Savillef6aa7c12009-04-30 14:20:52 -07002757 free(p_card_status);
2758}
2759
2760/**
The Android Open Source Project00f06fc2009-03-03 19:32:15 -08002761 * SIM ready means any commands that access the SIM will work, including:
2762 * AT+CPIN, AT+CSMS, AT+CNMI, AT+CRSM
2763 * (all SMS-related commands)
2764 */
2765
Mark Salyzynba58c202014-03-12 15:20:22 -07002766static void pollSIMState (void *param __unused)
The Android Open Source Project00f06fc2009-03-03 19:32:15 -08002767{
2768 ATResponse *p_response;
2769 int ret;
2770
Naveen Kalla2baf7232016-10-11 13:49:20 -07002771 if (sState != RADIO_STATE_UNAVAILABLE) {
The Android Open Source Project00f06fc2009-03-03 19:32:15 -08002772 // no longer valid to poll
2773 return;
2774 }
2775
2776 switch(getSIMStatus()) {
John Wang309ac292009-07-30 14:53:23 -07002777 case SIM_ABSENT:
2778 case SIM_PIN:
2779 case SIM_PUK:
2780 case SIM_NETWORK_PERSONALIZATION:
The Android Open Source Project00f06fc2009-03-03 19:32:15 -08002781 default:
Wink Saville4dcab4f2012-11-19 16:05:13 -08002782 RLOGI("SIM ABSENT or LOCKED");
Jaime A Lopez-Sollanoe9645042012-08-29 07:27:27 -07002783 RIL_onUnsolicitedResponse(RIL_UNSOL_RESPONSE_SIM_STATUS_CHANGED, NULL, 0);
The Android Open Source Project00f06fc2009-03-03 19:32:15 -08002784 return;
2785
John Wang309ac292009-07-30 14:53:23 -07002786 case SIM_NOT_READY:
The Android Open Source Project00f06fc2009-03-03 19:32:15 -08002787 RIL_requestTimedCallback (pollSIMState, NULL, &TIMEVAL_SIMPOLL);
2788 return;
2789
John Wang309ac292009-07-30 14:53:23 -07002790 case SIM_READY:
Wink Saville4dcab4f2012-11-19 16:05:13 -08002791 RLOGI("SIM_READY");
Jaime A Lopez-Sollanoe9645042012-08-29 07:27:27 -07002792 onSIMReady();
2793 RIL_onUnsolicitedResponse(RIL_UNSOL_RESPONSE_SIM_STATUS_CHANGED, NULL, 0);
The Android Open Source Project00f06fc2009-03-03 19:32:15 -08002794 return;
2795 }
2796}
2797
2798/** returns 1 if on, 0 if off, and -1 on error */
2799static int isRadioOn()
2800{
2801 ATResponse *p_response = NULL;
2802 int err;
2803 char *line;
2804 char ret;
2805
2806 err = at_send_command_singleline("AT+CFUN?", "+CFUN:", &p_response);
2807
2808 if (err < 0 || p_response->success == 0) {
2809 // assume radio is off
2810 goto error;
2811 }
2812
2813 line = p_response->p_intermediates->line;
2814
2815 err = at_tok_start(&line);
2816 if (err < 0) goto error;
2817
2818 err = at_tok_nextbool(&line, &ret);
2819 if (err < 0) goto error;
2820
2821 at_response_free(p_response);
2822
2823 return (int)ret;
2824
2825error:
2826
2827 at_response_free(p_response);
2828 return -1;
2829}
2830
2831/**
Jaime A Lopez-Sollanoe9645042012-08-29 07:27:27 -07002832 * Parse the response generated by a +CTEC AT command
2833 * The values read from the response are stored in current and preferred.
2834 * Both current and preferred may be null. The corresponding value is ignored in that case.
2835 *
2836 * @return: -1 if some error occurs (or if the modem doesn't understand the +CTEC command)
2837 * 1 if the response includes the current technology only
2838 * 0 if the response includes both current technology and preferred mode
2839 */
2840int parse_technology_response( const char *response, int *current, int32_t *preferred )
2841{
2842 int err;
2843 char *line, *p;
2844 int ct;
2845 int32_t pt = 0;
2846 char *str_pt;
2847
2848 line = p = strdup(response);
Wink Saville4dcab4f2012-11-19 16:05:13 -08002849 RLOGD("Response: %s", line);
Jaime A Lopez-Sollanoe9645042012-08-29 07:27:27 -07002850 err = at_tok_start(&p);
2851 if (err || !at_tok_hasmore(&p)) {
Wink Saville4dcab4f2012-11-19 16:05:13 -08002852 RLOGD("err: %d. p: %s", err, p);
Jaime A Lopez-Sollanoe9645042012-08-29 07:27:27 -07002853 free(line);
2854 return -1;
2855 }
2856
2857 err = at_tok_nextint(&p, &ct);
2858 if (err) {
2859 free(line);
2860 return -1;
2861 }
2862 if (current) *current = ct;
2863
Wink Saville4dcab4f2012-11-19 16:05:13 -08002864 RLOGD("line remaining after int: %s", p);
Jaime A Lopez-Sollanoe9645042012-08-29 07:27:27 -07002865
2866 err = at_tok_nexthexint(&p, &pt);
2867 if (err) {
2868 free(line);
2869 return 1;
2870 }
2871 if (preferred) {
2872 *preferred = pt;
2873 }
2874 free(line);
2875
2876 return 0;
2877}
2878
Mark Salyzynba58c202014-03-12 15:20:22 -07002879int query_supported_techs( ModemInfo *mdm __unused, int *supported )
Jaime A Lopez-Sollanoe9645042012-08-29 07:27:27 -07002880{
2881 ATResponse *p_response;
2882 int err, val, techs = 0;
2883 char *tok;
2884 char *line;
2885
Wink Saville4dcab4f2012-11-19 16:05:13 -08002886 RLOGD("query_supported_techs");
Jaime A Lopez-Sollanoe9645042012-08-29 07:27:27 -07002887 err = at_send_command_singleline("AT+CTEC=?", "+CTEC:", &p_response);
2888 if (err || !p_response->success)
2889 goto error;
2890 line = p_response->p_intermediates->line;
2891 err = at_tok_start(&line);
2892 if (err || !at_tok_hasmore(&line))
2893 goto error;
2894 while (!at_tok_nextint(&line, &val)) {
2895 techs |= ( 1 << val );
2896 }
2897 if (supported) *supported = techs;
2898 return 0;
2899error:
2900 at_response_free(p_response);
2901 return -1;
2902}
2903
2904/**
2905 * query_ctec. Send the +CTEC AT command to the modem to query the current
2906 * and preferred modes. It leaves values in the addresses pointed to by
2907 * current and preferred. If any of those pointers are NULL, the corresponding value
2908 * is ignored, but the return value will still reflect if retreiving and parsing of the
2909 * values suceeded.
2910 *
2911 * @mdm Currently unused
2912 * @current A pointer to store the current mode returned by the modem. May be null.
2913 * @preferred A pointer to store the preferred mode returned by the modem. May be null.
2914 * @return -1 on error (or failure to parse)
2915 * 1 if only the current mode was returned by modem (or failed to parse preferred)
2916 * 0 if both current and preferred were returned correctly
2917 */
Mark Salyzynba58c202014-03-12 15:20:22 -07002918int query_ctec(ModemInfo *mdm __unused, int *current, int32_t *preferred)
Jaime A Lopez-Sollanoe9645042012-08-29 07:27:27 -07002919{
2920 ATResponse *response = NULL;
2921 int err;
2922 int res;
2923
Colin Cross5cba4882014-02-05 18:55:42 -08002924 RLOGD("query_ctec. current: %p, preferred: %p", current, preferred);
Jaime A Lopez-Sollanoe9645042012-08-29 07:27:27 -07002925 err = at_send_command_singleline("AT+CTEC?", "+CTEC:", &response);
2926 if (!err && response->success) {
2927 res = parse_technology_response(response->p_intermediates->line, current, preferred);
2928 at_response_free(response);
2929 return res;
2930 }
Colin Cross5cba4882014-02-05 18:55:42 -08002931 RLOGE("Error executing command: %d. response: %p. status: %d", err, response, response? response->success : -1);
Jaime A Lopez-Sollanoe9645042012-08-29 07:27:27 -07002932 at_response_free(response);
2933 return -1;
2934}
2935
2936int is_multimode_modem(ModemInfo *mdm)
2937{
2938 ATResponse *response;
2939 int err;
2940 char *line;
2941 int tech;
2942 int32_t preferred;
2943
2944 if (query_ctec(mdm, &tech, &preferred) == 0) {
2945 mdm->currentTech = tech;
2946 mdm->preferredNetworkMode = preferred;
2947 if (query_supported_techs(mdm, &mdm->supportedTechs)) {
2948 return 0;
2949 }
2950 return 1;
2951 }
2952 return 0;
2953}
2954
2955/**
2956 * Find out if our modem is GSM, CDMA or both (Multimode)
2957 */
2958static void probeForModemMode(ModemInfo *info)
2959{
2960 ATResponse *response;
2961 int err;
2962 assert (info);
2963 // Currently, our only known multimode modem is qemu's android modem,
2964 // which implements the AT+CTEC command to query and set mode.
2965 // Try that first
2966
2967 if (is_multimode_modem(info)) {
Wink Saville4dcab4f2012-11-19 16:05:13 -08002968 RLOGI("Found Multimode Modem. Supported techs mask: %8.8x. Current tech: %d",
Jaime A Lopez-Sollanoe9645042012-08-29 07:27:27 -07002969 info->supportedTechs, info->currentTech);
2970 return;
2971 }
2972
2973 /* Being here means that our modem is not multimode */
2974 info->isMultimode = 0;
2975
2976 /* CDMA Modems implement the AT+WNAM command */
2977 err = at_send_command_singleline("AT+WNAM","+WNAM:", &response);
2978 if (!err && response->success) {
2979 at_response_free(response);
2980 // TODO: find out if we really support EvDo
2981 info->supportedTechs = MDM_CDMA | MDM_EVDO;
2982 info->currentTech = MDM_CDMA;
Wink Saville4dcab4f2012-11-19 16:05:13 -08002983 RLOGI("Found CDMA Modem");
Jaime A Lopez-Sollanoe9645042012-08-29 07:27:27 -07002984 return;
2985 }
2986 if (!err) at_response_free(response);
2987 // TODO: find out if modem really supports WCDMA/LTE
2988 info->supportedTechs = MDM_GSM | MDM_WCDMA | MDM_LTE;
2989 info->currentTech = MDM_GSM;
Wink Saville4dcab4f2012-11-19 16:05:13 -08002990 RLOGI("Found GSM Modem");
Jaime A Lopez-Sollanoe9645042012-08-29 07:27:27 -07002991}
2992
2993/**
The Android Open Source Project00f06fc2009-03-03 19:32:15 -08002994 * Initialize everything that can be configured while we're still in
2995 * AT+CFUN=0
2996 */
Mark Salyzynba58c202014-03-12 15:20:22 -07002997static void initializeCallback(void *param __unused)
The Android Open Source Project00f06fc2009-03-03 19:32:15 -08002998{
2999 ATResponse *p_response = NULL;
3000 int err;
3001
3002 setRadioState (RADIO_STATE_OFF);
3003
3004 at_handshake();
3005
Jaime A Lopez-Sollanoe9645042012-08-29 07:27:27 -07003006 probeForModemMode(sMdmInfo);
The Android Open Source Project00f06fc2009-03-03 19:32:15 -08003007 /* note: we don't check errors here. Everything important will
3008 be handled in onATTimeout and onATReaderClosed */
3009
3010 /* atchannel is tolerant of echo but it must */
3011 /* have verbose result codes */
3012 at_send_command("ATE0Q0V1", NULL);
3013
3014 /* No auto-answer */
3015 at_send_command("ATS0=0", NULL);
3016
3017 /* Extended errors */
3018 at_send_command("AT+CMEE=1", NULL);
3019
3020 /* Network registration events */
3021 err = at_send_command("AT+CREG=2", &p_response);
3022
3023 /* some handsets -- in tethered mode -- don't support CREG=2 */
3024 if (err < 0 || p_response->success == 0) {
3025 at_send_command("AT+CREG=1", NULL);
3026 }
3027
3028 at_response_free(p_response);
3029
3030 /* GPRS registration events */
3031 at_send_command("AT+CGREG=1", NULL);
3032
3033 /* Call Waiting notifications */
3034 at_send_command("AT+CCWA=1", NULL);
3035
3036 /* Alternating voice/data off */
3037 at_send_command("AT+CMOD=0", NULL);
3038
3039 /* Not muted */
3040 at_send_command("AT+CMUT=0", NULL);
3041
3042 /* +CSSU unsolicited supp service notifications */
3043 at_send_command("AT+CSSN=0,1", NULL);
3044
3045 /* no connected line identification */
3046 at_send_command("AT+COLP=0", NULL);
3047
3048 /* HEX character set */
3049 at_send_command("AT+CSCS=\"HEX\"", NULL);
3050
3051 /* USSD unsolicited */
3052 at_send_command("AT+CUSD=1", NULL);
3053
3054 /* Enable +CGEV GPRS event notifications, but don't buffer */
3055 at_send_command("AT+CGEREP=1,0", NULL);
3056
3057 /* SMS PDU mode */
3058 at_send_command("AT+CMGF=0", NULL);
3059
3060#ifdef USE_TI_COMMANDS
3061
3062 at_send_command("AT%CPI=3", NULL);
3063
3064 /* TI specific -- notifications when SMS is ready (currently ignored) */
3065 at_send_command("AT%CSTAT=1", NULL);
3066
3067#endif /* USE_TI_COMMANDS */
3068
3069
3070 /* assume radio is off on error */
3071 if (isRadioOn() > 0) {
Jaime A Lopez-Sollanoe9645042012-08-29 07:27:27 -07003072 setRadioState (RADIO_STATE_ON);
The Android Open Source Project00f06fc2009-03-03 19:32:15 -08003073 }
3074}
3075
3076static void waitForClose()
3077{
3078 pthread_mutex_lock(&s_state_mutex);
3079
3080 while (s_closed == 0) {
3081 pthread_cond_wait(&s_state_cond, &s_state_mutex);
3082 }
3083
3084 pthread_mutex_unlock(&s_state_mutex);
3085}
3086
Sukanya Rajkhowaa18b9d12013-09-10 12:30:13 -07003087static void sendUnsolImsNetworkStateChanged()
3088{
3089#if 0 // to be used when unsol is changed to return data.
3090 int reply[2];
3091 reply[0] = s_ims_registered;
3092 reply[1] = s_ims_services;
3093 reply[1] = s_ims_format;
3094#endif
3095 RIL_onUnsolicitedResponse(RIL_UNSOL_RESPONSE_IMS_NETWORK_STATE_CHANGED,
3096 NULL, 0);
3097}
3098
The Android Open Source Project00f06fc2009-03-03 19:32:15 -08003099/**
3100 * Called by atchannel when an unsolicited line appears
3101 * This is called on atchannel's reader thread. AT commands may
3102 * not be issued here
3103 */
3104static void onUnsolicited (const char *s, const char *sms_pdu)
3105{
Jaime A Lopez-Sollanoe9645042012-08-29 07:27:27 -07003106 char *line = NULL, *p;
The Android Open Source Project00f06fc2009-03-03 19:32:15 -08003107 int err;
3108
3109 /* Ignore unsolicited responses until we're initialized.
3110 * This is OK because the RIL library will poll for initial state
3111 */
3112 if (sState == RADIO_STATE_UNAVAILABLE) {
3113 return;
3114 }
3115
3116 if (strStartsWith(s, "%CTZV:")) {
3117 /* TI specific -- NITZ time */
3118 char *response;
3119
Jaime A Lopez-Sollanoe9645042012-08-29 07:27:27 -07003120 line = p = strdup(s);
3121 at_tok_start(&p);
The Android Open Source Project00f06fc2009-03-03 19:32:15 -08003122
Jaime A Lopez-Sollanoe9645042012-08-29 07:27:27 -07003123 err = at_tok_nextstr(&p, &response);
The Android Open Source Project00f06fc2009-03-03 19:32:15 -08003124
3125 if (err != 0) {
Wink Saville4dcab4f2012-11-19 16:05:13 -08003126 RLOGE("invalid NITZ line %s\n", s);
The Android Open Source Project00f06fc2009-03-03 19:32:15 -08003127 } else {
3128 RIL_onUnsolicitedResponse (
3129 RIL_UNSOL_NITZ_TIME_RECEIVED,
3130 response, strlen(response));
3131 }
Ivan Krasine18b85c2016-01-27 11:17:58 -08003132 free(line);
The Android Open Source Project00f06fc2009-03-03 19:32:15 -08003133 } else if (strStartsWith(s,"+CRING:")
3134 || strStartsWith(s,"RING")
3135 || strStartsWith(s,"NO CARRIER")
3136 || strStartsWith(s,"+CCWA")
3137 ) {
3138 RIL_onUnsolicitedResponse (
3139 RIL_UNSOL_RESPONSE_CALL_STATE_CHANGED,
3140 NULL, 0);
3141#ifdef WORKAROUND_FAKE_CGEV
Wink Savillef4c4d362009-04-02 01:37:03 -07003142 RIL_requestTimedCallback (onDataCallListChanged, NULL, NULL); //TODO use new function
The Android Open Source Project00f06fc2009-03-03 19:32:15 -08003143#endif /* WORKAROUND_FAKE_CGEV */
3144 } else if (strStartsWith(s,"+CREG:")
3145 || strStartsWith(s,"+CGREG:")
3146 ) {
3147 RIL_onUnsolicitedResponse (
Wink Saville2c1fb3a2011-03-19 13:42:45 -07003148 RIL_UNSOL_RESPONSE_VOICE_NETWORK_STATE_CHANGED,
The Android Open Source Project00f06fc2009-03-03 19:32:15 -08003149 NULL, 0);
3150#ifdef WORKAROUND_FAKE_CGEV
Wink Saville7f856802009-06-09 10:23:37 -07003151 RIL_requestTimedCallback (onDataCallListChanged, NULL, NULL);
The Android Open Source Project00f06fc2009-03-03 19:32:15 -08003152#endif /* WORKAROUND_FAKE_CGEV */
3153 } else if (strStartsWith(s, "+CMT:")) {
3154 RIL_onUnsolicitedResponse (
3155 RIL_UNSOL_RESPONSE_NEW_SMS,
3156 sms_pdu, strlen(sms_pdu));
3157 } else if (strStartsWith(s, "+CDS:")) {
3158 RIL_onUnsolicitedResponse (
3159 RIL_UNSOL_RESPONSE_NEW_SMS_STATUS_REPORT,
3160 sms_pdu, strlen(sms_pdu));
3161 } else if (strStartsWith(s, "+CGEV:")) {
3162 /* Really, we can ignore NW CLASS and ME CLASS events here,
3163 * but right now we don't since extranous
Wink Savillef4c4d362009-04-02 01:37:03 -07003164 * RIL_UNSOL_DATA_CALL_LIST_CHANGED calls are tolerated
The Android Open Source Project00f06fc2009-03-03 19:32:15 -08003165 */
3166 /* can't issue AT commands here -- call on main thread */
Wink Savillef4c4d362009-04-02 01:37:03 -07003167 RIL_requestTimedCallback (onDataCallListChanged, NULL, NULL);
The Android Open Source Project00f06fc2009-03-03 19:32:15 -08003168#ifdef WORKAROUND_FAKE_CGEV
3169 } else if (strStartsWith(s, "+CME ERROR: 150")) {
Wink Savillef4c4d362009-04-02 01:37:03 -07003170 RIL_requestTimedCallback (onDataCallListChanged, NULL, NULL);
The Android Open Source Project00f06fc2009-03-03 19:32:15 -08003171#endif /* WORKAROUND_FAKE_CGEV */
Jaime A Lopez-Sollanoe9645042012-08-29 07:27:27 -07003172 } else if (strStartsWith(s, "+CTEC: ")) {
3173 int tech, mask;
3174 switch (parse_technology_response(s, &tech, NULL))
3175 {
3176 case -1: // no argument could be parsed.
Wink Saville4dcab4f2012-11-19 16:05:13 -08003177 RLOGE("invalid CTEC line %s\n", s);
Jaime A Lopez-Sollanoe9645042012-08-29 07:27:27 -07003178 break;
3179 case 1: // current mode correctly parsed
3180 case 0: // preferred mode correctly parsed
3181 mask = 1 << tech;
3182 if (mask != MDM_GSM && mask != MDM_CDMA &&
3183 mask != MDM_WCDMA && mask != MDM_LTE) {
Wink Saville4dcab4f2012-11-19 16:05:13 -08003184 RLOGE("Unknown technology %d\n", tech);
Jaime A Lopez-Sollanoe9645042012-08-29 07:27:27 -07003185 } else {
3186 setRadioTechnology(sMdmInfo, tech);
3187 }
3188 break;
3189 }
3190 } else if (strStartsWith(s, "+CCSS: ")) {
3191 int source = 0;
3192 line = p = strdup(s);
3193 if (!line) {
Wink Saville4dcab4f2012-11-19 16:05:13 -08003194 RLOGE("+CCSS: Unable to allocate memory");
Jaime A Lopez-Sollanoe9645042012-08-29 07:27:27 -07003195 return;
3196 }
3197 if (at_tok_start(&p) < 0) {
3198 free(line);
3199 return;
3200 }
3201 if (at_tok_nextint(&p, &source) < 0) {
Wink Saville4dcab4f2012-11-19 16:05:13 -08003202 RLOGE("invalid +CCSS response: %s", line);
Jaime A Lopez-Sollanoe9645042012-08-29 07:27:27 -07003203 free(line);
3204 return;
3205 }
3206 SSOURCE(sMdmInfo) = source;
3207 RIL_onUnsolicitedResponse(RIL_UNSOL_CDMA_SUBSCRIPTION_SOURCE_CHANGED,
3208 &source, sizeof(source));
3209 } else if (strStartsWith(s, "+WSOS: ")) {
3210 char state = 0;
3211 int unsol;
3212 line = p = strdup(s);
3213 if (!line) {
Wink Saville4dcab4f2012-11-19 16:05:13 -08003214 RLOGE("+WSOS: Unable to allocate memory");
Jaime A Lopez-Sollanoe9645042012-08-29 07:27:27 -07003215 return;
3216 }
3217 if (at_tok_start(&p) < 0) {
3218 free(line);
3219 return;
3220 }
3221 if (at_tok_nextbool(&p, &state) < 0) {
Wink Saville4dcab4f2012-11-19 16:05:13 -08003222 RLOGE("invalid +WSOS response: %s", line);
Jaime A Lopez-Sollanoe9645042012-08-29 07:27:27 -07003223 free(line);
3224 return;
3225 }
3226 free(line);
3227
3228 unsol = state ?
3229 RIL_UNSOL_ENTER_EMERGENCY_CALLBACK_MODE : RIL_UNSOL_EXIT_EMERGENCY_CALLBACK_MODE;
3230
3231 RIL_onUnsolicitedResponse(unsol, NULL, 0);
3232
3233 } else if (strStartsWith(s, "+WPRL: ")) {
3234 int version = -1;
3235 line = p = strdup(s);
3236 if (!line) {
Wink Saville4dcab4f2012-11-19 16:05:13 -08003237 RLOGE("+WPRL: Unable to allocate memory");
Jaime A Lopez-Sollanoe9645042012-08-29 07:27:27 -07003238 return;
3239 }
3240 if (at_tok_start(&p) < 0) {
Wink Saville4dcab4f2012-11-19 16:05:13 -08003241 RLOGE("invalid +WPRL response: %s", s);
Jaime A Lopez-Sollanoe9645042012-08-29 07:27:27 -07003242 free(line);
3243 return;
3244 }
3245 if (at_tok_nextint(&p, &version) < 0) {
Wink Saville4dcab4f2012-11-19 16:05:13 -08003246 RLOGE("invalid +WPRL response: %s", s);
Jaime A Lopez-Sollanoe9645042012-08-29 07:27:27 -07003247 free(line);
3248 return;
3249 }
3250 free(line);
3251 RIL_onUnsolicitedResponse(RIL_UNSOL_CDMA_PRL_CHANGED, &version, sizeof(version));
3252 } else if (strStartsWith(s, "+CFUN: 0")) {
3253 setRadioState(RADIO_STATE_OFF);
The Android Open Source Project00f06fc2009-03-03 19:32:15 -08003254 }
3255}
3256
3257/* Called on command or reader thread */
3258static void onATReaderClosed()
3259{
Wink Saville4dcab4f2012-11-19 16:05:13 -08003260 RLOGI("AT channel closed\n");
The Android Open Source Project00f06fc2009-03-03 19:32:15 -08003261 at_close();
3262 s_closed = 1;
3263
3264 setRadioState (RADIO_STATE_UNAVAILABLE);
3265}
3266
3267/* Called on command thread */
3268static void onATTimeout()
3269{
Wink Saville4dcab4f2012-11-19 16:05:13 -08003270 RLOGI("AT channel timeout; closing\n");
The Android Open Source Project00f06fc2009-03-03 19:32:15 -08003271 at_close();
3272
3273 s_closed = 1;
3274
3275 /* FIXME cause a radio reset here */
3276
3277 setRadioState (RADIO_STATE_UNAVAILABLE);
3278}
3279
Etan Cohend3652192014-06-20 08:28:44 -07003280/* Called to pass hardware configuration information to telephony
3281 * framework.
3282 */
3283static void setHardwareConfiguration(int num, RIL_HardwareConfig *cfg)
3284{
3285 RIL_onUnsolicitedResponse(RIL_UNSOL_HARDWARE_CONFIG_CHANGED, cfg, num*sizeof(*cfg));
3286}
3287
Sanket Padawef0c8ca72016-06-30 15:01:08 -07003288static void usage(char *s __unused)
The Android Open Source Project00f06fc2009-03-03 19:32:15 -08003289{
3290#ifdef RIL_SHLIB
3291 fprintf(stderr, "reference-ril requires: -p <tcp port> or -d /dev/tty_device\n");
3292#else
3293 fprintf(stderr, "usage: %s [-p <tcp port>] [-d /dev/tty_device]\n", s);
3294 exit(-1);
3295#endif
3296}
3297
3298static void *
Mark Salyzynba58c202014-03-12 15:20:22 -07003299mainLoop(void *param __unused)
The Android Open Source Project00f06fc2009-03-03 19:32:15 -08003300{
3301 int fd;
3302 int ret;
3303
3304 AT_DUMP("== ", "entering mainLoop()", -1 );
3305 at_set_on_reader_closed(onATReaderClosed);
3306 at_set_on_timeout(onATTimeout);
3307
3308 for (;;) {
3309 fd = -1;
3310 while (fd < 0) {
David 'Digit' Turner834eca82016-06-22 12:10:01 +02003311 if (isInEmulator()) {
3312 fd = qemu_pipe_open("pipe:qemud:gsm");
3313 } else if (s_port > 0) {
Elliott Hughes7e3bbd42016-10-11 13:50:06 -07003314 fd = socket_network_client("localhost", s_port, SOCK_STREAM);
The Android Open Source Project00f06fc2009-03-03 19:32:15 -08003315 } else if (s_device_socket) {
David 'Digit' Turner834eca82016-06-22 12:10:01 +02003316 fd = socket_local_client(s_device_path,
3317 ANDROID_SOCKET_NAMESPACE_FILESYSTEM,
3318 SOCK_STREAM);
The Android Open Source Project00f06fc2009-03-03 19:32:15 -08003319 } else if (s_device_path != NULL) {
3320 fd = open (s_device_path, O_RDWR);
3321 if ( fd >= 0 && !memcmp( s_device_path, "/dev/ttyS", 9 ) ) {
3322 /* disable echo on serial ports */
3323 struct termios ios;
3324 tcgetattr( fd, &ios );
3325 ios.c_lflag = 0; /* disable ECHO, ICANON, etc... */
3326 tcsetattr( fd, TCSANOW, &ios );
3327 }
3328 }
3329
3330 if (fd < 0) {
3331 perror ("opening AT interface. retrying...");
3332 sleep(10);
3333 /* never returns */
3334 }
3335 }
3336
3337 s_closed = 0;
3338 ret = at_open(fd, onUnsolicited);
3339
3340 if (ret < 0) {
Wink Saville4dcab4f2012-11-19 16:05:13 -08003341 RLOGE ("AT error %d on at_open\n", ret);
The Android Open Source Project00f06fc2009-03-03 19:32:15 -08003342 return 0;
3343 }
3344
3345 RIL_requestTimedCallback(initializeCallback, NULL, &TIMEVAL_0);
3346
3347 // Give initializeCallback a chance to dispatched, since
3348 // we don't presently have a cancellation mechanism
3349 sleep(1);
3350
3351 waitForClose();
Wink Saville4dcab4f2012-11-19 16:05:13 -08003352 RLOGI("Re-opening after close");
The Android Open Source Project00f06fc2009-03-03 19:32:15 -08003353 }
3354}
3355
3356#ifdef RIL_SHLIB
3357
3358pthread_t s_tid_mainloop;
3359
3360const RIL_RadioFunctions *RIL_Init(const struct RIL_Env *env, int argc, char **argv)
3361{
3362 int ret;
3363 int fd = -1;
3364 int opt;
3365 pthread_attr_t attr;
3366
3367 s_rilenv = env;
3368
Sandeep Gutta11f27942014-07-10 05:00:25 +05303369 while ( -1 != (opt = getopt(argc, argv, "p:d:s:c:"))) {
The Android Open Source Project00f06fc2009-03-03 19:32:15 -08003370 switch (opt) {
3371 case 'p':
3372 s_port = atoi(optarg);
3373 if (s_port == 0) {
3374 usage(argv[0]);
3375 return NULL;
3376 }
Wink Saville4dcab4f2012-11-19 16:05:13 -08003377 RLOGI("Opening loopback port %d\n", s_port);
The Android Open Source Project00f06fc2009-03-03 19:32:15 -08003378 break;
3379
3380 case 'd':
3381 s_device_path = optarg;
Wink Saville4dcab4f2012-11-19 16:05:13 -08003382 RLOGI("Opening tty device %s\n", s_device_path);
The Android Open Source Project00f06fc2009-03-03 19:32:15 -08003383 break;
3384
3385 case 's':
3386 s_device_path = optarg;
3387 s_device_socket = 1;
Wink Saville4dcab4f2012-11-19 16:05:13 -08003388 RLOGI("Opening socket %s\n", s_device_path);
The Android Open Source Project00f06fc2009-03-03 19:32:15 -08003389 break;
3390
Sandeep Gutta11f27942014-07-10 05:00:25 +05303391 case 'c':
3392 RLOGI("Client id received %s\n", optarg);
3393 break;
3394
The Android Open Source Project00f06fc2009-03-03 19:32:15 -08003395 default:
3396 usage(argv[0]);
3397 return NULL;
3398 }
3399 }
3400
David 'Digit' Turner834eca82016-06-22 12:10:01 +02003401 if (s_port < 0 && s_device_path == NULL && !isInEmulator()) {
The Android Open Source Project00f06fc2009-03-03 19:32:15 -08003402 usage(argv[0]);
3403 return NULL;
3404 }
3405
Jaime A Lopez-Sollanoe9645042012-08-29 07:27:27 -07003406 sMdmInfo = calloc(1, sizeof(ModemInfo));
3407 if (!sMdmInfo) {
Wink Saville4dcab4f2012-11-19 16:05:13 -08003408 RLOGE("Unable to alloc memory for ModemInfo");
Jaime A Lopez-Sollanoe9645042012-08-29 07:27:27 -07003409 return NULL;
3410 }
The Android Open Source Project00f06fc2009-03-03 19:32:15 -08003411 pthread_attr_init (&attr);
3412 pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
3413 ret = pthread_create(&s_tid_mainloop, &attr, mainLoop, NULL);
3414
3415 return &s_callbacks;
3416}
3417#else /* RIL_SHLIB */
3418int main (int argc, char **argv)
3419{
3420 int ret;
3421 int fd = -1;
3422 int opt;
3423
3424 while ( -1 != (opt = getopt(argc, argv, "p:d:"))) {
3425 switch (opt) {
3426 case 'p':
3427 s_port = atoi(optarg);
3428 if (s_port == 0) {
3429 usage(argv[0]);
3430 }
Wink Saville4dcab4f2012-11-19 16:05:13 -08003431 RLOGI("Opening loopback port %d\n", s_port);
The Android Open Source Project00f06fc2009-03-03 19:32:15 -08003432 break;
3433
3434 case 'd':
3435 s_device_path = optarg;
Wink Saville4dcab4f2012-11-19 16:05:13 -08003436 RLOGI("Opening tty device %s\n", s_device_path);
The Android Open Source Project00f06fc2009-03-03 19:32:15 -08003437 break;
3438
3439 case 's':
3440 s_device_path = optarg;
3441 s_device_socket = 1;
Wink Saville4dcab4f2012-11-19 16:05:13 -08003442 RLOGI("Opening socket %s\n", s_device_path);
The Android Open Source Project00f06fc2009-03-03 19:32:15 -08003443 break;
3444
3445 default:
3446 usage(argv[0]);
3447 }
3448 }
3449
David 'Digit' Turner834eca82016-06-22 12:10:01 +02003450 if (s_port < 0 && s_device_path == NULL && !isInEmulator()) {
The Android Open Source Project00f06fc2009-03-03 19:32:15 -08003451 usage(argv[0]);
3452 }
3453
3454 RIL_register(&s_callbacks);
3455
3456 mainLoop(NULL);
3457
3458 return 0;
3459}
3460
3461#endif /* RIL_SHLIB */