blob: 8b79f625b6a823dda2f86045ba39944f19243a1a [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>
The Android Open Source Project00f06fc2009-03-03 19:32:15 -080020#include <stdio.h>
21#include <assert.h>
22#include <string.h>
23#include <errno.h>
24#include <unistd.h>
Mark Salyzynba58c202014-03-12 15:20:22 -070025#include <sys/cdefs.h>
The Android Open Source Project00f06fc2009-03-03 19:32:15 -080026#include <sys/types.h>
27#include <sys/stat.h>
Bjoern Johansson1fdedbd2016-10-27 16:36:29 -070028#include <inttypes.h>
The Android Open Source Project00f06fc2009-03-03 19:32:15 -080029#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>
David 'Digit' Turneraf1298d2011-02-04 13:36:47 +010038#include <sys/system_properties.h>
Weilun Du9f471e22017-02-07 10:47:19 -080039#include <termios.h>
bohuba723ce2017-03-29 12:20:46 -070040#include <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
Wink Saville8a9e0212013-04-09 12:11:38 -0700244static int s_cell_info_rate_ms = INT_MAX;
245static int s_mcc = 0;
246static int s_mnc = 0;
247static int s_lac = 0;
248static int s_cid = 0;
249
The Android Open Source Project00f06fc2009-03-03 19:32:15 -0800250static void pollSIMState (void *param);
251static void setRadioState(RIL_RadioState newState);
Jaime A Lopez-Sollanoe9645042012-08-29 07:27:27 -0700252static void setRadioTechnology(ModemInfo *mdm, int newtech);
253static int query_ctec(ModemInfo *mdm, int *current, int32_t *preferred);
254static int parse_technology_response(const char *response, int *current, int32_t *preferred);
255static int techFromModemType(int mdmtype);
The Android Open Source Project00f06fc2009-03-03 19:32:15 -0800256
257static int clccStateToRILState(int state, RIL_CallState *p_state)
258
259{
260 switch(state) {
261 case 0: *p_state = RIL_CALL_ACTIVE; return 0;
262 case 1: *p_state = RIL_CALL_HOLDING; return 0;
263 case 2: *p_state = RIL_CALL_DIALING; return 0;
264 case 3: *p_state = RIL_CALL_ALERTING; return 0;
265 case 4: *p_state = RIL_CALL_INCOMING; return 0;
266 case 5: *p_state = RIL_CALL_WAITING; return 0;
267 default: return -1;
268 }
269}
270
271/**
272 * Note: directly modified line and has *p_call point directly into
273 * modified line
274 */
Wink Saville3d54e742009-05-18 18:00:44 -0700275static int callFromCLCCLine(char *line, RIL_Call *p_call)
The Android Open Source Project00f06fc2009-03-03 19:32:15 -0800276{
277 //+CLCC: 1,0,2,0,0,\"+18005551212\",145
278 // index,isMT,state,mode,isMpty(,number,TOA)?
279
280 int err;
281 int state;
282 int mode;
283
284 err = at_tok_start(&line);
285 if (err < 0) goto error;
286
287 err = at_tok_nextint(&line, &(p_call->index));
288 if (err < 0) goto error;
289
290 err = at_tok_nextbool(&line, &(p_call->isMT));
291 if (err < 0) goto error;
292
293 err = at_tok_nextint(&line, &state);
294 if (err < 0) goto error;
295
296 err = clccStateToRILState(state, &(p_call->state));
297 if (err < 0) goto error;
298
299 err = at_tok_nextint(&line, &mode);
300 if (err < 0) goto error;
301
302 p_call->isVoice = (mode == 0);
303
304 err = at_tok_nextbool(&line, &(p_call->isMpty));
305 if (err < 0) goto error;
306
307 if (at_tok_hasmore(&line)) {
308 err = at_tok_nextstr(&line, &(p_call->number));
309
310 /* tolerate null here */
311 if (err < 0) return 0;
312
313 // Some lame implementations return strings
314 // like "NOT AVAILABLE" in the CLCC line
315 if (p_call->number != NULL
316 && 0 == strspn(p_call->number, "+0123456789")
317 ) {
318 p_call->number = NULL;
319 }
320
321 err = at_tok_nextint(&line, &p_call->toa);
322 if (err < 0) goto error;
323 }
324
Wink Saville74fa3882009-12-22 15:35:41 -0800325 p_call->uusInfo = NULL;
326
The Android Open Source Project00f06fc2009-03-03 19:32:15 -0800327 return 0;
328
329error:
Wink Saville4dcab4f2012-11-19 16:05:13 -0800330 RLOGE("invalid CLCC line\n");
The Android Open Source Project00f06fc2009-03-03 19:32:15 -0800331 return -1;
332}
333
Bjoern Johansson1fdedbd2016-10-27 16:36:29 -0700334static int parseSimResponseLine(char* line, RIL_SIM_IO_Response* response) {
335 int err;
336
337 err = at_tok_start(&line);
338 if (err < 0) return err;
339 err = at_tok_nextint(&line, &response->sw1);
340 if (err < 0) return err;
341 err = at_tok_nextint(&line, &response->sw2);
342 if (err < 0) return err;
343
344 if (at_tok_hasmore(&line)) {
345 err = at_tok_nextstr(&line, &response->simResponse);
346 if (err < 0) return err;
347 }
348 return 0;
349}
The Android Open Source Project00f06fc2009-03-03 19:32:15 -0800350
351/** do post-AT+CFUN=1 initialization */
352static void onRadioPowerOn()
353{
354#ifdef USE_TI_COMMANDS
355 /* Must be after CFUN=1 */
356 /* TI specific -- notifications for CPHS things such */
357 /* as CPHS message waiting indicator */
358
359 at_send_command("AT%CPHS=1", NULL);
360
361 /* TI specific -- enable NITZ unsol notifs */
362 at_send_command("AT%CTZV=1", NULL);
363#endif
364
365 pollSIMState(NULL);
366}
367
368/** do post- SIM ready initialization */
369static void onSIMReady()
370{
371 at_send_command_singleline("AT+CSMS=1", "+CSMS:", NULL);
372 /*
373 * Always send SMS messages directly to the TE
374 *
375 * mode = 1 // discard when link is reserved (link should never be
376 * reserved)
377 * mt = 2 // most messages routed to TE
378 * bm = 2 // new cell BM's routed to TE
379 * ds = 1 // Status reports routed to TE
380 * bfr = 1 // flush buffer
381 */
382 at_send_command("AT+CNMI=1,2,2,1,1", NULL);
383}
384
Sanket Padawef0c8ca72016-06-30 15:01:08 -0700385static void requestRadioPower(void *data, size_t datalen __unused, RIL_Token t)
The Android Open Source Project00f06fc2009-03-03 19:32:15 -0800386{
387 int onOff;
388
389 int err;
390 ATResponse *p_response = NULL;
391
392 assert (datalen >= sizeof(int *));
393 onOff = ((int *)data)[0];
394
395 if (onOff == 0 && sState != RADIO_STATE_OFF) {
396 err = at_send_command("AT+CFUN=0", &p_response);
397 if (err < 0 || p_response->success == 0) goto error;
398 setRadioState(RADIO_STATE_OFF);
399 } else if (onOff > 0 && sState == RADIO_STATE_OFF) {
400 err = at_send_command("AT+CFUN=1", &p_response);
401 if (err < 0|| p_response->success == 0) {
402 // Some stacks return an error when there is no SIM,
403 // but they really turn the RF portion on
404 // So, if we get an error, let's check to see if it
405 // turned on anyway
406
407 if (isRadioOn() != 1) {
408 goto error;
409 }
410 }
Jaime A Lopez-Sollanoe9645042012-08-29 07:27:27 -0700411 setRadioState(RADIO_STATE_ON);
The Android Open Source Project00f06fc2009-03-03 19:32:15 -0800412 }
413
414 at_response_free(p_response);
415 RIL_onRequestComplete(t, RIL_E_SUCCESS, NULL, 0);
416 return;
417error:
418 at_response_free(p_response);
419 RIL_onRequestComplete(t, RIL_E_GENERIC_FAILURE, NULL, 0);
420}
421
Naveen Kallaa65a16a2014-07-31 16:48:31 -0700422static void requestShutdown(RIL_Token t)
423{
424 int onOff;
425
426 int err;
427 ATResponse *p_response = NULL;
428
429 if (sState != RADIO_STATE_OFF) {
430 err = at_send_command("AT+CFUN=0", &p_response);
431 setRadioState(RADIO_STATE_UNAVAILABLE);
432 }
433
434 at_response_free(p_response);
435 RIL_onRequestComplete(t, RIL_E_SUCCESS, NULL, 0);
436 return;
437}
438
Wink Savillef4c4d362009-04-02 01:37:03 -0700439static void requestOrSendDataCallList(RIL_Token *t);
The Android Open Source Project00f06fc2009-03-03 19:32:15 -0800440
Mark Salyzynba58c202014-03-12 15:20:22 -0700441static void onDataCallListChanged(void *param __unused)
The Android Open Source Project00f06fc2009-03-03 19:32:15 -0800442{
Wink Savillef4c4d362009-04-02 01:37:03 -0700443 requestOrSendDataCallList(NULL);
The Android Open Source Project00f06fc2009-03-03 19:32:15 -0800444}
445
Mark Salyzynba58c202014-03-12 15:20:22 -0700446static void requestDataCallList(void *data __unused, size_t datalen __unused, RIL_Token t)
The Android Open Source Project00f06fc2009-03-03 19:32:15 -0800447{
Wink Savillef4c4d362009-04-02 01:37:03 -0700448 requestOrSendDataCallList(&t);
The Android Open Source Project00f06fc2009-03-03 19:32:15 -0800449}
450
Wink Savillef4c4d362009-04-02 01:37:03 -0700451static void requestOrSendDataCallList(RIL_Token *t)
The Android Open Source Project00f06fc2009-03-03 19:32:15 -0800452{
453 ATResponse *p_response;
454 ATLine *p_cur;
455 int err;
456 int n = 0;
457 char *out;
458
459 err = at_send_command_multiline ("AT+CGACT?", "+CGACT:", &p_response);
460 if (err != 0 || p_response->success == 0) {
461 if (t != NULL)
462 RIL_onRequestComplete(*t, RIL_E_GENERIC_FAILURE, NULL, 0);
463 else
Wink Savillef4c4d362009-04-02 01:37:03 -0700464 RIL_onUnsolicitedResponse(RIL_UNSOL_DATA_CALL_LIST_CHANGED,
The Android Open Source Project00f06fc2009-03-03 19:32:15 -0800465 NULL, 0);
466 return;
467 }
468
469 for (p_cur = p_response->p_intermediates; p_cur != NULL;
470 p_cur = p_cur->p_next)
471 n++;
472
Sukanya Rajkhowab44dda32014-06-02 14:03:44 -0700473 RIL_Data_Call_Response_v11 *responses =
474 alloca(n * sizeof(RIL_Data_Call_Response_v11));
The Android Open Source Project00f06fc2009-03-03 19:32:15 -0800475
476 int i;
477 for (i = 0; i < n; i++) {
Wink Saville43808972011-01-13 17:39:51 -0800478 responses[i].status = -1;
Wink Saville250eb3c2011-06-22 09:11:34 -0700479 responses[i].suggestedRetryTime = -1;
The Android Open Source Project00f06fc2009-03-03 19:32:15 -0800480 responses[i].cid = -1;
481 responses[i].active = -1;
482 responses[i].type = "";
Wink Saville43808972011-01-13 17:39:51 -0800483 responses[i].ifname = "";
484 responses[i].addresses = "";
485 responses[i].dnses = "";
Wink Saville2c1fb3a2011-03-19 13:42:45 -0700486 responses[i].gateways = "";
Etan Cohend3652192014-06-20 08:28:44 -0700487 responses[i].pcscf = "";
Sukanya Rajkhowab44dda32014-06-02 14:03:44 -0700488 responses[i].mtu = 0;
The Android Open Source Project00f06fc2009-03-03 19:32:15 -0800489 }
490
Sukanya Rajkhowab44dda32014-06-02 14:03:44 -0700491 RIL_Data_Call_Response_v11 *response = responses;
The Android Open Source Project00f06fc2009-03-03 19:32:15 -0800492 for (p_cur = p_response->p_intermediates; p_cur != NULL;
493 p_cur = p_cur->p_next) {
494 char *line = p_cur->line;
495
496 err = at_tok_start(&line);
497 if (err < 0)
498 goto error;
499
500 err = at_tok_nextint(&line, &response->cid);
501 if (err < 0)
502 goto error;
503
504 err = at_tok_nextint(&line, &response->active);
505 if (err < 0)
506 goto error;
507
508 response++;
509 }
510
511 at_response_free(p_response);
512
513 err = at_send_command_multiline ("AT+CGDCONT?", "+CGDCONT:", &p_response);
514 if (err != 0 || p_response->success == 0) {
515 if (t != NULL)
516 RIL_onRequestComplete(*t, RIL_E_GENERIC_FAILURE, NULL, 0);
517 else
Wink Savillef4c4d362009-04-02 01:37:03 -0700518 RIL_onUnsolicitedResponse(RIL_UNSOL_DATA_CALL_LIST_CHANGED,
The Android Open Source Project00f06fc2009-03-03 19:32:15 -0800519 NULL, 0);
520 return;
521 }
522
523 for (p_cur = p_response->p_intermediates; p_cur != NULL;
524 p_cur = p_cur->p_next) {
525 char *line = p_cur->line;
526 int cid;
The Android Open Source Project00f06fc2009-03-03 19:32:15 -0800527
528 err = at_tok_start(&line);
529 if (err < 0)
530 goto error;
531
532 err = at_tok_nextint(&line, &cid);
533 if (err < 0)
534 goto error;
535
536 for (i = 0; i < n; i++) {
537 if (responses[i].cid == cid)
538 break;
539 }
540
541 if (i >= n) {
542 /* details for a context we didn't hear about in the last request */
543 continue;
544 }
545
Wink Saville43808972011-01-13 17:39:51 -0800546 // Assume no error
547 responses[i].status = 0;
548
549 // type
The Android Open Source Project00f06fc2009-03-03 19:32:15 -0800550 err = at_tok_nextstr(&line, &out);
551 if (err < 0)
552 goto error;
Naina Nalluri2be38ac2016-05-03 14:09:53 -0700553
554 int type_size = strlen(out) + 1;
555 responses[i].type = alloca(type_size);
556 strlcpy(responses[i].type, out, type_size);
The Android Open Source Project00f06fc2009-03-03 19:32:15 -0800557
Wink Saville43808972011-01-13 17:39:51 -0800558 // APN ignored for v5
The Android Open Source Project00f06fc2009-03-03 19:32:15 -0800559 err = at_tok_nextstr(&line, &out);
560 if (err < 0)
561 goto error;
562
Naina Nalluri2be38ac2016-05-03 14:09:53 -0700563 int ifname_size = strlen(PPP_TTY_PATH) + 1;
564 responses[i].ifname = alloca(ifname_size);
565 strlcpy(responses[i].ifname, PPP_TTY_PATH, ifname_size);
The Android Open Source Project00f06fc2009-03-03 19:32:15 -0800566
567 err = at_tok_nextstr(&line, &out);
568 if (err < 0)
569 goto error;
570
Naina Nalluri2be38ac2016-05-03 14:09:53 -0700571 int addresses_size = strlen(out) + 1;
572 responses[i].addresses = alloca(addresses_size);
573 strlcpy(responses[i].addresses, out, addresses_size);
Wink Saville43808972011-01-13 17:39:51 -0800574
David 'Digit' Turner834eca82016-06-22 12:10:01 +0200575 if (isInEmulator()) {
576 /* We are in the emulator - the dns servers are listed
577 * by the following system properties, setup in
578 * /system/etc/init.goldfish.sh:
579 * - net.eth0.dns1
580 * - net.eth0.dns2
581 * - net.eth0.dns3
582 * - net.eth0.dns4
583 */
584 const int dnslist_sz = 128;
585 char* dnslist = alloca(dnslist_sz);
586 const char* separator = "";
587 int nn;
David 'Digit' Turneraf1298d2011-02-04 13:36:47 +0100588
David 'Digit' Turner834eca82016-06-22 12:10:01 +0200589 dnslist[0] = 0;
590 for (nn = 1; nn <= 4; nn++) {
591 /* Probe net.eth0.dns<n> */
592 char propName[PROP_NAME_MAX];
593 char propValue[PROP_VALUE_MAX];
David 'Digit' Turneraf1298d2011-02-04 13:36:47 +0100594
David 'Digit' Turner834eca82016-06-22 12:10:01 +0200595 snprintf(propName, sizeof propName, "net.eth0.dns%d", nn);
David 'Digit' Turneraf1298d2011-02-04 13:36:47 +0100596
David 'Digit' Turner834eca82016-06-22 12:10:01 +0200597 /* Ignore if undefined */
598 if (__system_property_get(propName, propValue) == 0) {
599 continue;
David 'Digit' Turneraf1298d2011-02-04 13:36:47 +0100600 }
Wink Saville2c1fb3a2011-03-19 13:42:45 -0700601
David 'Digit' Turner834eca82016-06-22 12:10:01 +0200602 /* Append the DNS IP address */
603 strlcat(dnslist, separator, dnslist_sz);
604 strlcat(dnslist, propValue, dnslist_sz);
605 separator = " ";
David 'Digit' Turneraf1298d2011-02-04 13:36:47 +0100606 }
David 'Digit' Turner834eca82016-06-22 12:10:01 +0200607 responses[i].dnses = dnslist;
608
609 /* There is only on gateway in the emulator */
610 responses[i].gateways = "10.0.2.2";
611 responses[i].mtu = DEFAULT_MTU;
612 }
613 else {
614 /* I don't know where we are, so use the public Google DNS
615 * servers by default and no gateway.
616 */
617 responses[i].dnses = "8.8.8.8 8.8.4.4";
618 responses[i].gateways = "";
David 'Digit' Turneraf1298d2011-02-04 13:36:47 +0100619 }
The Android Open Source Project00f06fc2009-03-03 19:32:15 -0800620 }
621
622 at_response_free(p_response);
623
624 if (t != NULL)
625 RIL_onRequestComplete(*t, RIL_E_SUCCESS, responses,
Sukanya Rajkhowab44dda32014-06-02 14:03:44 -0700626 n * sizeof(RIL_Data_Call_Response_v11));
The Android Open Source Project00f06fc2009-03-03 19:32:15 -0800627 else
Wink Savillef4c4d362009-04-02 01:37:03 -0700628 RIL_onUnsolicitedResponse(RIL_UNSOL_DATA_CALL_LIST_CHANGED,
The Android Open Source Project00f06fc2009-03-03 19:32:15 -0800629 responses,
Sukanya Rajkhowab44dda32014-06-02 14:03:44 -0700630 n * sizeof(RIL_Data_Call_Response_v11));
The Android Open Source Project00f06fc2009-03-03 19:32:15 -0800631
632 return;
633
634error:
635 if (t != NULL)
636 RIL_onRequestComplete(*t, RIL_E_GENERIC_FAILURE, NULL, 0);
637 else
Wink Savillef4c4d362009-04-02 01:37:03 -0700638 RIL_onUnsolicitedResponse(RIL_UNSOL_DATA_CALL_LIST_CHANGED,
The Android Open Source Project00f06fc2009-03-03 19:32:15 -0800639 NULL, 0);
640
641 at_response_free(p_response);
642}
643
644static void requestQueryNetworkSelectionMode(
Mark Salyzynba58c202014-03-12 15:20:22 -0700645 void *data __unused, size_t datalen __unused, RIL_Token t)
The Android Open Source Project00f06fc2009-03-03 19:32:15 -0800646{
647 int err;
648 ATResponse *p_response = NULL;
649 int response = 0;
650 char *line;
651
652 err = at_send_command_singleline("AT+COPS?", "+COPS:", &p_response);
653
654 if (err < 0 || p_response->success == 0) {
655 goto error;
656 }
657
658 line = p_response->p_intermediates->line;
659
660 err = at_tok_start(&line);
661
662 if (err < 0) {
663 goto error;
664 }
665
666 err = at_tok_nextint(&line, &response);
667
668 if (err < 0) {
669 goto error;
670 }
671
672 RIL_onRequestComplete(t, RIL_E_SUCCESS, &response, sizeof(int));
673 at_response_free(p_response);
674 return;
675error:
676 at_response_free(p_response);
Wink Saville4dcab4f2012-11-19 16:05:13 -0800677 RLOGE("requestQueryNetworkSelectionMode must never return error when radio is on");
The Android Open Source Project00f06fc2009-03-03 19:32:15 -0800678 RIL_onRequestComplete(t, RIL_E_GENERIC_FAILURE, NULL, 0);
679}
680
Mark Salyzynba58c202014-03-12 15:20:22 -0700681static void sendCallStateChanged(void *param __unused)
The Android Open Source Project00f06fc2009-03-03 19:32:15 -0800682{
683 RIL_onUnsolicitedResponse (
684 RIL_UNSOL_RESPONSE_CALL_STATE_CHANGED,
685 NULL, 0);
686}
687
Mark Salyzynba58c202014-03-12 15:20:22 -0700688static void requestGetCurrentCalls(void *data __unused, size_t datalen __unused, RIL_Token t)
The Android Open Source Project00f06fc2009-03-03 19:32:15 -0800689{
690 int err;
691 ATResponse *p_response;
692 ATLine *p_cur;
693 int countCalls;
694 int countValidCalls;
Wink Saville3d54e742009-05-18 18:00:44 -0700695 RIL_Call *p_calls;
696 RIL_Call **pp_calls;
The Android Open Source Project00f06fc2009-03-03 19:32:15 -0800697 int i;
698 int needRepoll = 0;
699
700#ifdef WORKAROUND_ERRONEOUS_ANSWER
701 int prevIncomingOrWaitingLine;
702
703 prevIncomingOrWaitingLine = s_incomingOrWaitingLine;
704 s_incomingOrWaitingLine = -1;
705#endif /*WORKAROUND_ERRONEOUS_ANSWER*/
706
707 err = at_send_command_multiline ("AT+CLCC", "+CLCC:", &p_response);
708
709 if (err != 0 || p_response->success == 0) {
710 RIL_onRequestComplete(t, RIL_E_GENERIC_FAILURE, NULL, 0);
711 return;
712 }
713
714 /* count the calls */
715 for (countCalls = 0, p_cur = p_response->p_intermediates
716 ; p_cur != NULL
717 ; p_cur = p_cur->p_next
718 ) {
719 countCalls++;
720 }
721
722 /* yes, there's an array of pointers and then an array of structures */
723
Wink Saville3d54e742009-05-18 18:00:44 -0700724 pp_calls = (RIL_Call **)alloca(countCalls * sizeof(RIL_Call *));
725 p_calls = (RIL_Call *)alloca(countCalls * sizeof(RIL_Call));
726 memset (p_calls, 0, countCalls * sizeof(RIL_Call));
The Android Open Source Project00f06fc2009-03-03 19:32:15 -0800727
728 /* init the pointer array */
729 for(i = 0; i < countCalls ; i++) {
730 pp_calls[i] = &(p_calls[i]);
731 }
732
733 for (countValidCalls = 0, p_cur = p_response->p_intermediates
734 ; p_cur != NULL
735 ; p_cur = p_cur->p_next
736 ) {
737 err = callFromCLCCLine(p_cur->line, p_calls + countValidCalls);
738
739 if (err != 0) {
740 continue;
741 }
742
743#ifdef WORKAROUND_ERRONEOUS_ANSWER
744 if (p_calls[countValidCalls].state == RIL_CALL_INCOMING
745 || p_calls[countValidCalls].state == RIL_CALL_WAITING
746 ) {
747 s_incomingOrWaitingLine = p_calls[countValidCalls].index;
748 }
749#endif /*WORKAROUND_ERRONEOUS_ANSWER*/
750
751 if (p_calls[countValidCalls].state != RIL_CALL_ACTIVE
752 && p_calls[countValidCalls].state != RIL_CALL_HOLDING
753 ) {
754 needRepoll = 1;
755 }
756
757 countValidCalls++;
758 }
759
760#ifdef WORKAROUND_ERRONEOUS_ANSWER
761 // Basically:
762 // A call was incoming or waiting
763 // Now it's marked as active
764 // But we never answered it
765 //
766 // This is probably a bug, and the call will probably
767 // disappear from the call list in the next poll
768 if (prevIncomingOrWaitingLine >= 0
769 && s_incomingOrWaitingLine < 0
770 && s_expectAnswer == 0
771 ) {
772 for (i = 0; i < countValidCalls ; i++) {
773
774 if (p_calls[i].index == prevIncomingOrWaitingLine
775 && p_calls[i].state == RIL_CALL_ACTIVE
776 && s_repollCallsCount < REPOLL_CALLS_COUNT_MAX
777 ) {
Wink Saville4dcab4f2012-11-19 16:05:13 -0800778 RLOGI(
The Android Open Source Project00f06fc2009-03-03 19:32:15 -0800779 "Hit WORKAROUND_ERRONOUS_ANSWER case."
780 " Repoll count: %d\n", s_repollCallsCount);
781 s_repollCallsCount++;
782 goto error;
783 }
784 }
785 }
786
787 s_expectAnswer = 0;
788 s_repollCallsCount = 0;
789#endif /*WORKAROUND_ERRONEOUS_ANSWER*/
790
Wink Saville3d54e742009-05-18 18:00:44 -0700791 RIL_onRequestComplete(t, RIL_E_SUCCESS, pp_calls,
792 countValidCalls * sizeof (RIL_Call *));
The Android Open Source Project00f06fc2009-03-03 19:32:15 -0800793
794 at_response_free(p_response);
795
796#ifdef POLL_CALL_STATE
797 if (countValidCalls) { // We don't seem to get a "NO CARRIER" message from
798 // smd, so we're forced to poll until the call ends.
799#else
800 if (needRepoll) {
801#endif
802 RIL_requestTimedCallback (sendCallStateChanged, NULL, &TIMEVAL_CALLSTATEPOLL);
803 }
804
805 return;
Tomasz Wasilczyk88961c22017-04-11 09:21:08 -0700806#ifdef WORKAROUND_ERRONEOUS_ANSWER
The Android Open Source Project00f06fc2009-03-03 19:32:15 -0800807error:
808 RIL_onRequestComplete(t, RIL_E_GENERIC_FAILURE, NULL, 0);
809 at_response_free(p_response);
Tomasz Wasilczyk88961c22017-04-11 09:21:08 -0700810#endif
The Android Open Source Project00f06fc2009-03-03 19:32:15 -0800811}
812
Mark Salyzynba58c202014-03-12 15:20:22 -0700813static void requestDial(void *data, size_t datalen __unused, RIL_Token t)
The Android Open Source Project00f06fc2009-03-03 19:32:15 -0800814{
815 RIL_Dial *p_dial;
816 char *cmd;
817 const char *clir;
818 int ret;
819
820 p_dial = (RIL_Dial *)data;
821
822 switch (p_dial->clir) {
823 case 1: clir = "I"; break; /*invocation*/
824 case 2: clir = "i"; break; /*suppression*/
825 default:
826 case 0: clir = ""; break; /*subscription default*/
827 }
828
829 asprintf(&cmd, "ATD%s%s;", p_dial->address, clir);
830
831 ret = at_send_command(cmd, NULL);
832
833 free(cmd);
834
835 /* success or failure is ignored by the upper layer here.
836 it will call GET_CURRENT_CALLS and determine success that way */
837 RIL_onRequestComplete(t, RIL_E_SUCCESS, NULL, 0);
838}
839
Mark Salyzynba58c202014-03-12 15:20:22 -0700840static void requestWriteSmsToSim(void *data, size_t datalen __unused, RIL_Token t)
The Android Open Source Project00f06fc2009-03-03 19:32:15 -0800841{
842 RIL_SMS_WriteArgs *p_args;
843 char *cmd;
844 int length;
845 int err;
846 ATResponse *p_response = NULL;
847
848 p_args = (RIL_SMS_WriteArgs *)data;
849
850 length = strlen(p_args->pdu)/2;
851 asprintf(&cmd, "AT+CMGW=%d,%d", length, p_args->status);
852
853 err = at_send_command_sms(cmd, p_args->pdu, "+CMGW:", &p_response);
854
855 if (err != 0 || p_response->success == 0) goto error;
856
857 RIL_onRequestComplete(t, RIL_E_SUCCESS, NULL, 0);
858 at_response_free(p_response);
859
860 return;
861error:
862 RIL_onRequestComplete(t, RIL_E_GENERIC_FAILURE, NULL, 0);
863 at_response_free(p_response);
864}
865
Mark Salyzynba58c202014-03-12 15:20:22 -0700866static void requestHangup(void *data, size_t datalen __unused, RIL_Token t)
The Android Open Source Project00f06fc2009-03-03 19:32:15 -0800867{
868 int *p_line;
869
870 int ret;
871 char *cmd;
872
873 p_line = (int *)data;
874
875 // 3GPP 22.030 6.5.5
876 // "Releases a specific active call X"
877 asprintf(&cmd, "AT+CHLD=1%d", p_line[0]);
878
879 ret = at_send_command(cmd, NULL);
880
881 free(cmd);
882
883 /* success or failure is ignored by the upper layer here.
884 it will call GET_CURRENT_CALLS and determine success that way */
885 RIL_onRequestComplete(t, RIL_E_SUCCESS, NULL, 0);
886}
887
Mark Salyzynba58c202014-03-12 15:20:22 -0700888static void requestSignalStrength(void *data __unused, size_t datalen __unused, RIL_Token t)
The Android Open Source Project00f06fc2009-03-03 19:32:15 -0800889{
890 ATResponse *p_response = NULL;
891 int err;
The Android Open Source Project00f06fc2009-03-03 19:32:15 -0800892 char *line;
Jim Kayedc9f31b2017-04-03 13:43:31 -0700893 int count = 0;
894 // Accept a response that is at least v6, and up to v10
895 int minNumOfElements=sizeof(RIL_SignalStrength_v6)/sizeof(int);
896 int maxNumOfElements=sizeof(RIL_SignalStrength_v10)/sizeof(int);
897 int response[maxNumOfElements];
898
899 memset(response, 0, sizeof(response));
The Android Open Source Project00f06fc2009-03-03 19:32:15 -0800900
901 err = at_send_command_singleline("AT+CSQ", "+CSQ:", &p_response);
902
903 if (err < 0 || p_response->success == 0) {
904 RIL_onRequestComplete(t, RIL_E_GENERIC_FAILURE, NULL, 0);
905 goto error;
906 }
907
908 line = p_response->p_intermediates->line;
909
910 err = at_tok_start(&line);
911 if (err < 0) goto error;
912
Jim Kayedc9f31b2017-04-03 13:43:31 -0700913 for (count = 0; count < maxNumOfElements; count++) {
Uma Maheswari Ramalingam9efcac52012-08-09 11:59:17 -0700914 err = at_tok_nextint(&line, &(response[count]));
Jim Kayedc9f31b2017-04-03 13:43:31 -0700915 if (err < 0 && count < minNumOfElements) goto error;
Uma Maheswari Ramalingam9efcac52012-08-09 11:59:17 -0700916 }
Chih-Wei Huang28059052012-04-30 01:13:27 +0800917
Uma Maheswari Ramalingam9efcac52012-08-09 11:59:17 -0700918 RIL_onRequestComplete(t, RIL_E_SUCCESS, response, sizeof(response));
The Android Open Source Project00f06fc2009-03-03 19:32:15 -0800919
920 at_response_free(p_response);
921 return;
922
923error:
Wink Saville4dcab4f2012-11-19 16:05:13 -0800924 RLOGE("requestSignalStrength must never return an error when radio is on");
The Android Open Source Project00f06fc2009-03-03 19:32:15 -0800925 RIL_onRequestComplete(t, RIL_E_GENERIC_FAILURE, NULL, 0);
926 at_response_free(p_response);
927}
928
Jaime A Lopez-Sollanoe9645042012-08-29 07:27:27 -0700929/**
930 * networkModePossible. Decides whether the network mode is appropriate for the
931 * specified modem
932 */
933static int networkModePossible(ModemInfo *mdm, int nm)
934{
935 if ((net2modem[nm] & mdm->supportedTechs) == net2modem[nm]) {
936 return 1;
937 }
938 return 0;
939}
Mark Salyzynba58c202014-03-12 15:20:22 -0700940static void requestSetPreferredNetworkType( int request __unused, void *data,
941 size_t datalen __unused, RIL_Token t )
Jaime A Lopez-Sollanoe9645042012-08-29 07:27:27 -0700942{
943 ATResponse *p_response = NULL;
944 char *cmd = NULL;
945 int value = *(int *)data;
946 int current, old;
947 int err;
948 int32_t preferred = net2pmask[value];
949
Wink Saville4dcab4f2012-11-19 16:05:13 -0800950 RLOGD("requestSetPreferredNetworkType: current: %x. New: %x", PREFERRED_NETWORK(sMdmInfo), preferred);
Jaime A Lopez-Sollanoe9645042012-08-29 07:27:27 -0700951 if (!networkModePossible(sMdmInfo, value)) {
952 RIL_onRequestComplete(t, RIL_E_MODE_NOT_SUPPORTED, NULL, 0);
953 return;
954 }
955 if (query_ctec(sMdmInfo, &current, NULL) < 0) {
956 RIL_onRequestComplete(t, RIL_E_GENERIC_FAILURE, NULL, 0);
957 return;
958 }
959 old = PREFERRED_NETWORK(sMdmInfo);
Wink Saville4dcab4f2012-11-19 16:05:13 -0800960 RLOGD("old != preferred: %d", old != preferred);
Jaime A Lopez-Sollanoe9645042012-08-29 07:27:27 -0700961 if (old != preferred) {
962 asprintf(&cmd, "AT+CTEC=%d,\"%x\"", current, preferred);
Wink Saville4dcab4f2012-11-19 16:05:13 -0800963 RLOGD("Sending command: <%s>", cmd);
Jaime A Lopez-Sollanoe9645042012-08-29 07:27:27 -0700964 err = at_send_command_singleline(cmd, "+CTEC:", &p_response);
965 free(cmd);
966 if (err || !p_response->success) {
967 RIL_onRequestComplete(t, RIL_E_GENERIC_FAILURE, NULL, 0);
968 return;
969 }
970 PREFERRED_NETWORK(sMdmInfo) = value;
971 if (!strstr( p_response->p_intermediates->line, "DONE") ) {
972 int current;
973 int res = parse_technology_response(p_response->p_intermediates->line, &current, NULL);
974 switch (res) {
975 case -1: // Error or unable to parse
976 break;
977 case 1: // Only able to parse current
978 case 0: // Both current and preferred were parsed
979 setRadioTechnology(sMdmInfo, current);
980 break;
981 }
982 }
983 }
984 RIL_onRequestComplete(t, RIL_E_SUCCESS, NULL, 0);
985}
986
Mark Salyzynba58c202014-03-12 15:20:22 -0700987static void requestGetPreferredNetworkType(int request __unused, void *data __unused,
988 size_t datalen __unused, RIL_Token t)
Jaime A Lopez-Sollanoe9645042012-08-29 07:27:27 -0700989{
990 int preferred;
991 unsigned i;
992
993 switch ( query_ctec(sMdmInfo, NULL, &preferred) ) {
994 case -1: // Error or unable to parse
995 case 1: // Only able to parse current
996 RIL_onRequestComplete(t, RIL_E_GENERIC_FAILURE, NULL, 0);
997 break;
998 case 0: // Both current and preferred were parsed
999 for ( i = 0 ; i < sizeof(net2pmask) / sizeof(int32_t) ; i++ ) {
1000 if (preferred == net2pmask[i]) {
1001 RIL_onRequestComplete(t, RIL_E_SUCCESS, &i, sizeof(int));
1002 return;
1003 }
1004 }
Wink Saville4dcab4f2012-11-19 16:05:13 -08001005 RLOGE("Unknown preferred mode received from modem: %d", preferred);
Jaime A Lopez-Sollanoe9645042012-08-29 07:27:27 -07001006 RIL_onRequestComplete(t, RIL_E_GENERIC_FAILURE, NULL, 0);
1007 break;
1008 }
1009
1010}
1011
Mark Salyzynba58c202014-03-12 15:20:22 -07001012static void requestCdmaPrlVersion(int request __unused, void *data __unused,
1013 size_t datalen __unused, RIL_Token t)
Jaime A Lopez-Sollanoe9645042012-08-29 07:27:27 -07001014{
1015 int err;
1016 char * responseStr;
1017 ATResponse *p_response = NULL;
1018 const char *cmd;
1019 char *line;
1020
1021 err = at_send_command_singleline("AT+WPRL?", "+WPRL:", &p_response);
1022 if (err < 0 || !p_response->success) goto error;
1023 line = p_response->p_intermediates->line;
1024 err = at_tok_start(&line);
1025 if (err < 0) goto error;
1026 err = at_tok_nextstr(&line, &responseStr);
1027 if (err < 0 || !responseStr) goto error;
1028 RIL_onRequestComplete(t, RIL_E_SUCCESS, responseStr, strlen(responseStr));
1029 at_response_free(p_response);
1030 return;
1031error:
1032 at_response_free(p_response);
1033 RIL_onRequestComplete(t, RIL_E_GENERIC_FAILURE, NULL, 0);
1034}
1035
Mark Salyzynba58c202014-03-12 15:20:22 -07001036static void requestCdmaBaseBandVersion(int request __unused, void *data __unused,
1037 size_t datalen __unused, RIL_Token t)
Jaime A Lopez-Sollanoe9645042012-08-29 07:27:27 -07001038{
1039 int err;
1040 char * responseStr;
1041 ATResponse *p_response = NULL;
1042 const char *cmd;
1043 const char *prefix;
1044 char *line, *p;
1045 int commas;
1046 int skip;
1047 int count = 4;
1048
1049 // Fixed values. TODO: query modem
1050 responseStr = strdup("1.0.0.0");
1051 RIL_onRequestComplete(t, RIL_E_SUCCESS, responseStr, sizeof(responseStr));
1052 free(responseStr);
1053}
1054
Mark Salyzynba58c202014-03-12 15:20:22 -07001055static void requestCdmaDeviceIdentity(int request __unused, void *data __unused,
1056 size_t datalen __unused, RIL_Token t)
The Android Open Source Project00f06fc2009-03-03 19:32:15 -08001057{
1058 int err;
1059 int response[4];
1060 char * responseStr[4];
1061 ATResponse *p_response = NULL;
1062 const char *cmd;
1063 const char *prefix;
1064 char *line, *p;
1065 int commas;
1066 int skip;
Jaime A Lopez-Sollanoe9645042012-08-29 07:27:27 -07001067 int count = 4;
The Android Open Source Project00f06fc2009-03-03 19:32:15 -08001068
Jaime A Lopez-Sollanoe9645042012-08-29 07:27:27 -07001069 // Fixed values. TODO: Query modem
1070 responseStr[0] = "----";
1071 responseStr[1] = "----";
1072 responseStr[2] = "77777777";
The Android Open Source Project00f06fc2009-03-03 19:32:15 -08001073
Jaime A Lopez-Sollanoe9645042012-08-29 07:27:27 -07001074 err = at_send_command_numeric("AT+CGSN", &p_response);
1075 if (err < 0 || p_response->success == 0) {
1076 RIL_onRequestComplete(t, RIL_E_GENERIC_FAILURE, NULL, 0);
1077 return;
The Android Open Source Project00f06fc2009-03-03 19:32:15 -08001078 } else {
Jaime A Lopez-Sollanoe9645042012-08-29 07:27:27 -07001079 responseStr[3] = p_response->p_intermediates->line;
The Android Open Source Project00f06fc2009-03-03 19:32:15 -08001080 }
1081
Jaime A Lopez-Sollanoe9645042012-08-29 07:27:27 -07001082 RIL_onRequestComplete(t, RIL_E_SUCCESS, responseStr, count*sizeof(char*));
1083 at_response_free(p_response);
Jaime A Lopez-Sollanoe9645042012-08-29 07:27:27 -07001084}
1085
Mark Salyzynba58c202014-03-12 15:20:22 -07001086static void requestCdmaGetSubscriptionSource(int request __unused, void *data,
1087 size_t datalen __unused, RIL_Token t)
Jaime A Lopez-Sollanoe9645042012-08-29 07:27:27 -07001088{
1089 int err;
1090 int *ss = (int *)data;
1091 ATResponse *p_response = NULL;
1092 char *cmd = NULL;
1093 char *line = NULL;
1094 int response;
1095
1096 asprintf(&cmd, "AT+CCSS?");
1097 if (!cmd) goto error;
1098
1099 err = at_send_command_singleline(cmd, "+CCSS:", &p_response);
1100 if (err < 0 || !p_response->success)
1101 goto error;
The Android Open Source Project00f06fc2009-03-03 19:32:15 -08001102
1103 line = p_response->p_intermediates->line;
Jaime A Lopez-Sollanoe9645042012-08-29 07:27:27 -07001104 err = at_tok_start(&line);
1105 if (err < 0) goto error;
The Android Open Source Project00f06fc2009-03-03 19:32:15 -08001106
Jaime A Lopez-Sollanoe9645042012-08-29 07:27:27 -07001107 err = at_tok_nextint(&line, &response);
1108 free(cmd);
1109 cmd = NULL;
1110
1111 RIL_onRequestComplete(t, RIL_E_SUCCESS, &response, sizeof(response));
1112
1113 return;
1114error:
1115 free(cmd);
1116 RIL_onRequestComplete(t, RIL_E_GENERIC_FAILURE, NULL, 0);
1117}
1118
Mark Salyzynba58c202014-03-12 15:20:22 -07001119static void requestCdmaSetSubscriptionSource(int request __unused, void *data,
Jaime A Lopez-Sollanoe9645042012-08-29 07:27:27 -07001120 size_t datalen, RIL_Token t)
1121{
1122 int err;
1123 int *ss = (int *)data;
1124 ATResponse *p_response = NULL;
1125 char *cmd = NULL;
1126
1127 if (!ss || !datalen) {
Wink Saville4dcab4f2012-11-19 16:05:13 -08001128 RLOGE("RIL_REQUEST_CDMA_SET_SUBSCRIPTION without data!");
Jaime A Lopez-Sollanoe9645042012-08-29 07:27:27 -07001129 RIL_onRequestComplete(t, RIL_E_GENERIC_FAILURE, NULL, 0);
1130 return;
1131 }
1132 asprintf(&cmd, "AT+CCSS=%d", ss[0]);
1133 if (!cmd) goto error;
1134
1135 err = at_send_command(cmd, &p_response);
1136 if (err < 0 || !p_response->success)
1137 goto error;
1138 free(cmd);
1139 cmd = NULL;
1140
1141 RIL_onRequestComplete(t, RIL_E_SUCCESS, NULL, 0);
1142
1143 RIL_onUnsolicitedResponse(RIL_UNSOL_CDMA_SUBSCRIPTION_SOURCE_CHANGED, ss, sizeof(ss[0]));
1144
1145 return;
1146error:
1147 free(cmd);
1148 RIL_onRequestComplete(t, RIL_E_GENERIC_FAILURE, NULL, 0);
1149}
1150
Mark Salyzynba58c202014-03-12 15:20:22 -07001151static void requestCdmaSubscription(int request __unused, void *data __unused,
1152 size_t datalen __unused, RIL_Token t)
Jaime A Lopez-Sollanoe9645042012-08-29 07:27:27 -07001153{
1154 int err;
1155 int response[5];
1156 char * responseStr[5];
1157 ATResponse *p_response = NULL;
1158 const char *cmd;
1159 const char *prefix;
1160 char *line, *p;
1161 int commas;
1162 int skip;
1163 int count = 5;
1164
1165 // Fixed values. TODO: Query modem
1166 responseStr[0] = "8587777777"; // MDN
1167 responseStr[1] = "1"; // SID
1168 responseStr[2] = "1"; // NID
1169 responseStr[3] = "8587777777"; // MIN
1170 responseStr[4] = "1"; // PRL Version
1171 RIL_onRequestComplete(t, RIL_E_SUCCESS, responseStr, count*sizeof(char*));
Jaime A Lopez-Sollanoe9645042012-08-29 07:27:27 -07001172}
1173
Mark Salyzynba58c202014-03-12 15:20:22 -07001174static void requestCdmaGetRoamingPreference(int request __unused, void *data __unused,
1175 size_t datalen __unused, RIL_Token t)
Jaime A Lopez-Sollanoe9645042012-08-29 07:27:27 -07001176{
1177 int roaming_pref = -1;
1178 ATResponse *p_response = NULL;
1179 char *line;
1180 int res;
1181
1182 res = at_send_command_singleline("AT+WRMP?", "+WRMP:", &p_response);
1183 if (res < 0 || !p_response->success) {
1184 goto error;
1185 }
1186 line = p_response->p_intermediates->line;
1187
1188 res = at_tok_start(&line);
1189 if (res < 0) goto error;
1190
1191 res = at_tok_nextint(&line, &roaming_pref);
1192 if (res < 0) goto error;
1193
1194 RIL_onRequestComplete(t, RIL_E_SUCCESS, &roaming_pref, sizeof(roaming_pref));
1195 return;
1196error:
1197 RIL_onRequestComplete(t, RIL_E_GENERIC_FAILURE, NULL, 0);
1198}
1199
Mark Salyzynba58c202014-03-12 15:20:22 -07001200static void requestCdmaSetRoamingPreference(int request __unused, void *data,
1201 size_t datalen __unused, RIL_Token t)
Jaime A Lopez-Sollanoe9645042012-08-29 07:27:27 -07001202{
1203 int *pref = (int *)data;
1204 ATResponse *p_response = NULL;
1205 char *line;
1206 int res;
1207 char *cmd = NULL;
1208
1209 asprintf(&cmd, "AT+WRMP=%d", *pref);
1210 if (cmd == NULL) goto error;
1211
1212 res = at_send_command(cmd, &p_response);
1213 if (res < 0 || !p_response->success)
1214 goto error;
1215
1216 RIL_onRequestComplete(t, RIL_E_SUCCESS, NULL, 0);
1217 free(cmd);
1218 return;
1219error:
1220 free(cmd);
1221 RIL_onRequestComplete(t, RIL_E_GENERIC_FAILURE, NULL, 0);
1222}
1223
1224static int parseRegistrationState(char *str, int *type, int *items, int **response)
1225{
1226 int err;
1227 char *line = str, *p;
1228 int *resp = NULL;
1229 int skip;
1230 int count = 3;
1231 int commas;
1232
Wink Saville4dcab4f2012-11-19 16:05:13 -08001233 RLOGD("parseRegistrationState. Parsing: %s",str);
The Android Open Source Project00f06fc2009-03-03 19:32:15 -08001234 err = at_tok_start(&line);
1235 if (err < 0) goto error;
1236
1237 /* Ok you have to be careful here
1238 * The solicited version of the CREG response is
1239 * +CREG: n, stat, [lac, cid]
1240 * and the unsolicited version is
1241 * +CREG: stat, [lac, cid]
1242 * The <n> parameter is basically "is unsolicited creg on?"
1243 * which it should always be
1244 *
1245 * Now we should normally get the solicited version here,
1246 * but the unsolicited version could have snuck in
1247 * so we have to handle both
1248 *
1249 * Also since the LAC and CID are only reported when registered,
1250 * we can have 1, 2, 3, or 4 arguments here
1251 *
1252 * finally, a +CGREG: answer may have a fifth value that corresponds
1253 * to the network type, as in;
1254 *
1255 * +CGREG: n, stat [,lac, cid [,networkType]]
1256 */
1257
1258 /* count number of commas */
1259 commas = 0;
1260 for (p = line ; *p != '\0' ;p++) {
1261 if (*p == ',') commas++;
1262 }
1263
Jaime A Lopez-Sollanoe9645042012-08-29 07:27:27 -07001264 resp = (int *)calloc(commas + 1, sizeof(int));
1265 if (!resp) goto error;
The Android Open Source Project00f06fc2009-03-03 19:32:15 -08001266 switch (commas) {
1267 case 0: /* +CREG: <stat> */
Jaime A Lopez-Sollanoe9645042012-08-29 07:27:27 -07001268 err = at_tok_nextint(&line, &resp[0]);
The Android Open Source Project00f06fc2009-03-03 19:32:15 -08001269 if (err < 0) goto error;
Jaime A Lopez-Sollanoe9645042012-08-29 07:27:27 -07001270 resp[1] = -1;
1271 resp[2] = -1;
The Android Open Source Project00f06fc2009-03-03 19:32:15 -08001272 break;
1273
1274 case 1: /* +CREG: <n>, <stat> */
1275 err = at_tok_nextint(&line, &skip);
1276 if (err < 0) goto error;
Jaime A Lopez-Sollanoe9645042012-08-29 07:27:27 -07001277 err = at_tok_nextint(&line, &resp[0]);
The Android Open Source Project00f06fc2009-03-03 19:32:15 -08001278 if (err < 0) goto error;
Jaime A Lopez-Sollanoe9645042012-08-29 07:27:27 -07001279 resp[1] = -1;
1280 resp[2] = -1;
The Android Open Source Project00f06fc2009-03-03 19:32:15 -08001281 if (err < 0) goto error;
1282 break;
1283
1284 case 2: /* +CREG: <stat>, <lac>, <cid> */
Jaime A Lopez-Sollanoe9645042012-08-29 07:27:27 -07001285 err = at_tok_nextint(&line, &resp[0]);
The Android Open Source Project00f06fc2009-03-03 19:32:15 -08001286 if (err < 0) goto error;
Jaime A Lopez-Sollanoe9645042012-08-29 07:27:27 -07001287 err = at_tok_nexthexint(&line, &resp[1]);
The Android Open Source Project00f06fc2009-03-03 19:32:15 -08001288 if (err < 0) goto error;
Jaime A Lopez-Sollanoe9645042012-08-29 07:27:27 -07001289 err = at_tok_nexthexint(&line, &resp[2]);
The Android Open Source Project00f06fc2009-03-03 19:32:15 -08001290 if (err < 0) goto error;
1291 break;
1292 case 3: /* +CREG: <n>, <stat>, <lac>, <cid> */
1293 err = at_tok_nextint(&line, &skip);
1294 if (err < 0) goto error;
Jaime A Lopez-Sollanoe9645042012-08-29 07:27:27 -07001295 err = at_tok_nextint(&line, &resp[0]);
The Android Open Source Project00f06fc2009-03-03 19:32:15 -08001296 if (err < 0) goto error;
Jaime A Lopez-Sollanoe9645042012-08-29 07:27:27 -07001297 err = at_tok_nexthexint(&line, &resp[1]);
The Android Open Source Project00f06fc2009-03-03 19:32:15 -08001298 if (err < 0) goto error;
Jaime A Lopez-Sollanoe9645042012-08-29 07:27:27 -07001299 err = at_tok_nexthexint(&line, &resp[2]);
The Android Open Source Project00f06fc2009-03-03 19:32:15 -08001300 if (err < 0) goto error;
1301 break;
1302 /* special case for CGREG, there is a fourth parameter
1303 * that is the network type (unknown/gprs/edge/umts)
1304 */
1305 case 4: /* +CGREG: <n>, <stat>, <lac>, <cid>, <networkType> */
1306 err = at_tok_nextint(&line, &skip);
1307 if (err < 0) goto error;
Jaime A Lopez-Sollanoe9645042012-08-29 07:27:27 -07001308 err = at_tok_nextint(&line, &resp[0]);
The Android Open Source Project00f06fc2009-03-03 19:32:15 -08001309 if (err < 0) goto error;
Jaime A Lopez-Sollanoe9645042012-08-29 07:27:27 -07001310 err = at_tok_nexthexint(&line, &resp[1]);
The Android Open Source Project00f06fc2009-03-03 19:32:15 -08001311 if (err < 0) goto error;
Jaime A Lopez-Sollanoe9645042012-08-29 07:27:27 -07001312 err = at_tok_nexthexint(&line, &resp[2]);
The Android Open Source Project00f06fc2009-03-03 19:32:15 -08001313 if (err < 0) goto error;
Jaime A Lopez-Sollanoe9645042012-08-29 07:27:27 -07001314 err = at_tok_nexthexint(&line, &resp[3]);
The Android Open Source Project00f06fc2009-03-03 19:32:15 -08001315 if (err < 0) goto error;
1316 count = 4;
1317 break;
1318 default:
1319 goto error;
1320 }
Wink Saville8a9e0212013-04-09 12:11:38 -07001321 s_lac = resp[1];
1322 s_cid = resp[2];
Jaime A Lopez-Sollanoe9645042012-08-29 07:27:27 -07001323 if (response)
1324 *response = resp;
1325 if (items)
1326 *items = commas + 1;
1327 if (type)
1328 *type = techFromModemType(TECH(sMdmInfo));
1329 return 0;
1330error:
1331 free(resp);
1332 return -1;
1333}
The Android Open Source Project00f06fc2009-03-03 19:32:15 -08001334
Jaime A Lopez-Sollanoe9645042012-08-29 07:27:27 -07001335#define REG_STATE_LEN 15
1336#define REG_DATA_STATE_LEN 6
Mark Salyzynba58c202014-03-12 15:20:22 -07001337static void requestRegistrationState(int request, void *data __unused,
1338 size_t datalen __unused, RIL_Token t)
Jaime A Lopez-Sollanoe9645042012-08-29 07:27:27 -07001339{
1340 int err;
1341 int *registration;
1342 char **responseStr = NULL;
1343 ATResponse *p_response = NULL;
1344 const char *cmd;
1345 const char *prefix;
1346 char *line;
1347 int i = 0, j, numElements = 0;
1348 int count = 3;
1349 int type, startfrom;
The Android Open Source Project00f06fc2009-03-03 19:32:15 -08001350
Wink Saville4dcab4f2012-11-19 16:05:13 -08001351 RLOGD("requestRegistrationState");
Jaime A Lopez-Sollanoe9645042012-08-29 07:27:27 -07001352 if (request == RIL_REQUEST_VOICE_REGISTRATION_STATE) {
1353 cmd = "AT+CREG?";
1354 prefix = "+CREG:";
1355 numElements = REG_STATE_LEN;
1356 } else if (request == RIL_REQUEST_DATA_REGISTRATION_STATE) {
1357 cmd = "AT+CGREG?";
1358 prefix = "+CGREG:";
1359 numElements = REG_DATA_STATE_LEN;
1360 } else {
1361 assert(0);
1362 goto error;
1363 }
The Android Open Source Project00f06fc2009-03-03 19:32:15 -08001364
Jaime A Lopez-Sollanoe9645042012-08-29 07:27:27 -07001365 err = at_send_command_singleline(cmd, prefix, &p_response);
1366
1367 if (err != 0) goto error;
1368
1369 line = p_response->p_intermediates->line;
1370
1371 if (parseRegistrationState(line, &type, &count, &registration)) goto error;
1372
1373 responseStr = malloc(numElements * sizeof(char *));
1374 if (!responseStr) goto error;
1375 memset(responseStr, 0, numElements * sizeof(char *));
1376 /**
1377 * The first '4' bytes for both registration states remain the same.
1378 * But if the request is 'DATA_REGISTRATION_STATE',
1379 * the 5th and 6th byte(s) are optional.
1380 */
1381 if (is3gpp2(type) == 1) {
Wink Saville4dcab4f2012-11-19 16:05:13 -08001382 RLOGD("registration state type: 3GPP2");
Jaime A Lopez-Sollanoe9645042012-08-29 07:27:27 -07001383 // TODO: Query modem
1384 startfrom = 3;
1385 if(request == RIL_REQUEST_VOICE_REGISTRATION_STATE) {
1386 asprintf(&responseStr[3], "8"); // EvDo revA
1387 asprintf(&responseStr[4], "1"); // BSID
1388 asprintf(&responseStr[5], "123"); // Latitude
1389 asprintf(&responseStr[6], "222"); // Longitude
1390 asprintf(&responseStr[7], "0"); // CSS Indicator
1391 asprintf(&responseStr[8], "4"); // SID
1392 asprintf(&responseStr[9], "65535"); // NID
1393 asprintf(&responseStr[10], "0"); // Roaming indicator
1394 asprintf(&responseStr[11], "1"); // System is in PRL
1395 asprintf(&responseStr[12], "0"); // Default Roaming indicator
1396 asprintf(&responseStr[13], "0"); // Reason for denial
1397 asprintf(&responseStr[14], "0"); // Primary Scrambling Code of Current cell
1398 } else if (request == RIL_REQUEST_DATA_REGISTRATION_STATE) {
1399 asprintf(&responseStr[3], "8"); // Available data radio technology
1400 }
1401 } else { // type == RADIO_TECH_3GPP
Wink Saville4dcab4f2012-11-19 16:05:13 -08001402 RLOGD("registration state type: 3GPP");
Jaime A Lopez-Sollanoe9645042012-08-29 07:27:27 -07001403 startfrom = 0;
1404 asprintf(&responseStr[1], "%x", registration[1]);
1405 asprintf(&responseStr[2], "%x", registration[2]);
1406 if (count > 3)
1407 asprintf(&responseStr[3], "%d", registration[3]);
1408 }
1409 asprintf(&responseStr[0], "%d", registration[0]);
1410
1411 /**
1412 * Optional bytes for DATA_REGISTRATION_STATE request
1413 * 4th byte : Registration denial code
1414 * 5th byte : The max. number of simultaneous Data Calls
1415 */
1416 if(request == RIL_REQUEST_DATA_REGISTRATION_STATE) {
1417 // asprintf(&responseStr[4], "3");
1418 // asprintf(&responseStr[5], "1");
1419 }
1420
1421 for (j = startfrom; j < numElements; j++) {
1422 if (!responseStr[i]) goto error;
1423 }
1424 free(registration);
1425 registration = NULL;
1426
1427 RIL_onRequestComplete(t, RIL_E_SUCCESS, responseStr, numElements*sizeof(responseStr));
1428 for (j = 0; j < numElements; j++ ) {
1429 free(responseStr[j]);
1430 responseStr[j] = NULL;
1431 }
1432 free(responseStr);
1433 responseStr = NULL;
The Android Open Source Project00f06fc2009-03-03 19:32:15 -08001434 at_response_free(p_response);
1435
1436 return;
1437error:
Jaime A Lopez-Sollanoe9645042012-08-29 07:27:27 -07001438 if (responseStr) {
1439 for (j = 0; j < numElements; j++) {
1440 free(responseStr[j]);
1441 responseStr[j] = NULL;
1442 }
1443 free(responseStr);
1444 responseStr = NULL;
1445 }
Wink Saville4dcab4f2012-11-19 16:05:13 -08001446 RLOGE("requestRegistrationState must never return an error when radio is on");
The Android Open Source Project00f06fc2009-03-03 19:32:15 -08001447 RIL_onRequestComplete(t, RIL_E_GENERIC_FAILURE, NULL, 0);
1448 at_response_free(p_response);
1449}
1450
Mark Salyzynba58c202014-03-12 15:20:22 -07001451static void requestOperator(void *data __unused, size_t datalen __unused, RIL_Token t)
The Android Open Source Project00f06fc2009-03-03 19:32:15 -08001452{
1453 int err;
1454 int i;
1455 int skip;
1456 ATLine *p_cur;
1457 char *response[3];
1458
1459 memset(response, 0, sizeof(response));
1460
1461 ATResponse *p_response = NULL;
1462
1463 err = at_send_command_multiline(
1464 "AT+COPS=3,0;+COPS?;+COPS=3,1;+COPS?;+COPS=3,2;+COPS?",
1465 "+COPS:", &p_response);
1466
1467 /* we expect 3 lines here:
1468 * +COPS: 0,0,"T - Mobile"
1469 * +COPS: 0,1,"TMO"
1470 * +COPS: 0,2,"310170"
1471 */
1472
1473 if (err != 0) goto error;
1474
1475 for (i = 0, p_cur = p_response->p_intermediates
1476 ; p_cur != NULL
1477 ; p_cur = p_cur->p_next, i++
1478 ) {
1479 char *line = p_cur->line;
1480
1481 err = at_tok_start(&line);
1482 if (err < 0) goto error;
1483
1484 err = at_tok_nextint(&line, &skip);
1485 if (err < 0) goto error;
1486
1487 // If we're unregistered, we may just get
1488 // a "+COPS: 0" response
1489 if (!at_tok_hasmore(&line)) {
1490 response[i] = NULL;
1491 continue;
1492 }
1493
1494 err = at_tok_nextint(&line, &skip);
1495 if (err < 0) goto error;
1496
1497 // a "+COPS: 0, n" response is also possible
1498 if (!at_tok_hasmore(&line)) {
1499 response[i] = NULL;
1500 continue;
1501 }
1502
1503 err = at_tok_nextstr(&line, &(response[i]));
1504 if (err < 0) goto error;
Wink Saville8a9e0212013-04-09 12:11:38 -07001505 // Simple assumption that mcc and mnc are 3 digits each
1506 if (strlen(response[i]) == 6) {
1507 if (sscanf(response[i], "%3d%3d", &s_mcc, &s_mnc) != 2) {
1508 RLOGE("requestOperator expected mccmnc to be 6 decimal digits");
1509 }
1510 }
The Android Open Source Project00f06fc2009-03-03 19:32:15 -08001511 }
1512
1513 if (i != 3) {
1514 /* expect 3 lines exactly */
1515 goto error;
1516 }
1517
1518 RIL_onRequestComplete(t, RIL_E_SUCCESS, response, sizeof(response));
1519 at_response_free(p_response);
1520
1521 return;
1522error:
Wink Saville4dcab4f2012-11-19 16:05:13 -08001523 RLOGE("requestOperator must not return error when radio is on");
The Android Open Source Project00f06fc2009-03-03 19:32:15 -08001524 RIL_onRequestComplete(t, RIL_E_GENERIC_FAILURE, NULL, 0);
1525 at_response_free(p_response);
1526}
1527
Jaime A Lopez-Sollanoe9645042012-08-29 07:27:27 -07001528static void requestCdmaSendSMS(void *data, size_t datalen, RIL_Token t)
1529{
1530 int err = 1; // Set to go to error:
1531 RIL_SMS_Response response;
1532 RIL_CDMA_SMS_Message* rcsm;
1533
Mark Salyzynba58c202014-03-12 15:20:22 -07001534 RLOGD("requestCdmaSendSMS datalen=%zu, sizeof(RIL_CDMA_SMS_Message)=%zu",
Jaime A Lopez-Sollanoe9645042012-08-29 07:27:27 -07001535 datalen, sizeof(RIL_CDMA_SMS_Message));
1536
1537 // verify data content to test marshalling/unmarshalling:
1538 rcsm = (RIL_CDMA_SMS_Message*)data;
Wink Saville4dcab4f2012-11-19 16:05:13 -08001539 RLOGD("TeleserviceID=%d, bIsServicePresent=%d, \
Jaime A Lopez-Sollanoe9645042012-08-29 07:27:27 -07001540 uServicecategory=%d, sAddress.digit_mode=%d, \
1541 sAddress.Number_mode=%d, sAddress.number_type=%d, ",
1542 rcsm->uTeleserviceID, rcsm->bIsServicePresent,
1543 rcsm->uServicecategory,rcsm->sAddress.digit_mode,
1544 rcsm->sAddress.number_mode,rcsm->sAddress.number_type);
1545
1546 if (err != 0) goto error;
1547
1548 // Cdma Send SMS implementation will go here:
1549 // But it is not implemented yet.
1550
1551 memset(&response, 0, sizeof(response));
Sukanya Rajkhowaa18b9d12013-09-10 12:30:13 -07001552 response.messageRef = 1;
Jaime A Lopez-Sollanoe9645042012-08-29 07:27:27 -07001553 RIL_onRequestComplete(t, RIL_E_SUCCESS, &response, sizeof(response));
1554 return;
1555
1556error:
1557 // Cdma Send SMS will always cause send retry error.
Sukanya Rajkhowaa18b9d12013-09-10 12:30:13 -07001558 response.messageRef = -1;
1559 RIL_onRequestComplete(t, RIL_E_SMS_SEND_FAIL_RETRY, &response, sizeof(response));
Jaime A Lopez-Sollanoe9645042012-08-29 07:27:27 -07001560}
1561
The Android Open Source Project00f06fc2009-03-03 19:32:15 -08001562static void requestSendSMS(void *data, size_t datalen, RIL_Token t)
1563{
1564 int err;
1565 const char *smsc;
1566 const char *pdu;
1567 int tpLayerLength;
1568 char *cmd1, *cmd2;
1569 RIL_SMS_Response response;
1570 ATResponse *p_response = NULL;
1571
Sukanya Rajkhowaa18b9d12013-09-10 12:30:13 -07001572 memset(&response, 0, sizeof(response));
Mark Salyzynba58c202014-03-12 15:20:22 -07001573 RLOGD("requestSendSMS datalen =%zu", datalen);
Sukanya Rajkhowaa18b9d12013-09-10 12:30:13 -07001574
1575 if (s_ims_gsm_fail != 0) goto error;
1576 if (s_ims_gsm_retry != 0) goto error2;
1577
The Android Open Source Project00f06fc2009-03-03 19:32:15 -08001578 smsc = ((const char **)data)[0];
1579 pdu = ((const char **)data)[1];
1580
1581 tpLayerLength = strlen(pdu)/2;
1582
1583 // "NULL for default SMSC"
1584 if (smsc == NULL) {
1585 smsc= "00";
1586 }
1587
1588 asprintf(&cmd1, "AT+CMGS=%d", tpLayerLength);
1589 asprintf(&cmd2, "%s%s", smsc, pdu);
1590
1591 err = at_send_command_sms(cmd1, cmd2, "+CMGS:", &p_response);
1592
Daniele Palmasa5c743e2015-05-06 11:47:59 +02001593 free(cmd1);
1594 free(cmd2);
1595
The Android Open Source Project00f06fc2009-03-03 19:32:15 -08001596 if (err != 0 || p_response->success == 0) goto error;
1597
The Android Open Source Project00f06fc2009-03-03 19:32:15 -08001598 /* FIXME fill in messageRef and ackPDU */
Sukanya Rajkhowaa18b9d12013-09-10 12:30:13 -07001599 response.messageRef = 1;
The Android Open Source Project00f06fc2009-03-03 19:32:15 -08001600 RIL_onRequestComplete(t, RIL_E_SUCCESS, &response, sizeof(response));
1601 at_response_free(p_response);
1602
1603 return;
1604error:
Sukanya Rajkhowaa18b9d12013-09-10 12:30:13 -07001605 response.messageRef = -2;
1606 RIL_onRequestComplete(t, RIL_E_GENERIC_FAILURE, &response, sizeof(response));
The Android Open Source Project00f06fc2009-03-03 19:32:15 -08001607 at_response_free(p_response);
Sukanya Rajkhowaa18b9d12013-09-10 12:30:13 -07001608 return;
1609error2:
1610 // send retry error.
1611 response.messageRef = -1;
1612 RIL_onRequestComplete(t, RIL_E_SMS_SEND_FAIL_RETRY, &response, sizeof(response));
1613 at_response_free(p_response);
1614 return;
1615 }
1616
1617static void requestImsSendSMS(void *data, size_t datalen, RIL_Token t)
1618{
1619 RIL_IMS_SMS_Message *p_args;
1620 RIL_SMS_Response response;
1621
1622 memset(&response, 0, sizeof(response));
1623
Mark Salyzynba58c202014-03-12 15:20:22 -07001624 RLOGD("requestImsSendSMS: datalen=%zu, "
Sukanya Rajkhowaa18b9d12013-09-10 12:30:13 -07001625 "registered=%d, service=%d, format=%d, ims_perm_fail=%d, "
1626 "ims_retry=%d, gsm_fail=%d, gsm_retry=%d",
1627 datalen, s_ims_registered, s_ims_services, s_ims_format,
1628 s_ims_cause_perm_failure, s_ims_cause_retry, s_ims_gsm_fail,
1629 s_ims_gsm_retry);
1630
1631 // figure out if this is gsm/cdma format
1632 // then route it to requestSendSMS vs requestCdmaSendSMS respectively
1633 p_args = (RIL_IMS_SMS_Message *)data;
1634
1635 if (0 != s_ims_cause_perm_failure ) goto error;
1636
1637 // want to fail over ims and this is first request over ims
1638 if (0 != s_ims_cause_retry && 0 == p_args->retry) goto error2;
1639
1640 if (RADIO_TECH_3GPP == p_args->tech) {
1641 return requestSendSMS(p_args->message.gsmMessage,
1642 datalen - sizeof(RIL_RadioTechnologyFamily),
1643 t);
1644 } else if (RADIO_TECH_3GPP2 == p_args->tech) {
1645 return requestCdmaSendSMS(p_args->message.cdmaMessage,
1646 datalen - sizeof(RIL_RadioTechnologyFamily),
1647 t);
1648 } else {
1649 RLOGE("requestImsSendSMS invalid format value =%d", p_args->tech);
1650 }
1651
1652error:
1653 response.messageRef = -2;
1654 RIL_onRequestComplete(t, RIL_E_GENERIC_FAILURE, &response, sizeof(response));
1655 return;
1656
1657error2:
1658 response.messageRef = -1;
1659 RIL_onRequestComplete(t, RIL_E_SMS_SEND_FAIL_RETRY, &response, sizeof(response));
The Android Open Source Project00f06fc2009-03-03 19:32:15 -08001660}
1661
Bjoern Johansson1fdedbd2016-10-27 16:36:29 -07001662static void requestSimOpenChannel(void *data, size_t datalen, RIL_Token t)
1663{
1664 ATResponse *p_response = NULL;
1665 int32_t session_id;
1666 int err;
1667 char cmd[32];
1668 char dummy;
1669 char *line;
1670
1671 // Max length is 16 bytes according to 3GPP spec 27.007 section 8.45
1672 if (data == NULL || datalen == 0 || datalen > 16) {
1673 ALOGE("Invalid data passed to requestSimOpenChannel");
1674 RIL_onRequestComplete(t, RIL_E_GENERIC_FAILURE, NULL, 0);
1675 return;
1676 }
1677
1678 snprintf(cmd, sizeof(cmd), "AT+CCHO=%s", data);
1679
1680 err = at_send_command_numeric(cmd, &p_response);
1681 if (err < 0 || p_response == NULL || p_response->success == 0) {
1682 ALOGE("Error %d opening logical channel: %d",
1683 err, p_response ? p_response->success : 0);
1684 RIL_onRequestComplete(t, RIL_E_GENERIC_FAILURE, NULL, 0);
1685 at_response_free(p_response);
1686 return;
1687 }
1688
1689 // Ensure integer only by scanning for an extra char but expect one result
1690 line = p_response->p_intermediates->line;
1691 if (sscanf(line, "%" SCNd32 "%c", &session_id, &dummy) != 1) {
1692 ALOGE("Invalid AT response, expected integer, was '%s'", line);
1693 RIL_onRequestComplete(t, RIL_E_GENERIC_FAILURE, NULL, 0);
1694 return;
1695 }
1696
1697 RIL_onRequestComplete(t, RIL_E_SUCCESS, &session_id, sizeof(&session_id));
1698 at_response_free(p_response);
1699}
1700
1701static void requestSimCloseChannel(void *data, size_t datalen, RIL_Token t)
1702{
1703 ATResponse *p_response = NULL;
1704 int32_t session_id;
1705 int err;
1706 char cmd[32];
1707
1708 if (data == NULL || datalen != sizeof(session_id)) {
1709 ALOGE("Invalid data passed to requestSimCloseChannel");
1710 RIL_onRequestComplete(t, RIL_E_GENERIC_FAILURE, NULL, 0);
1711 return;
1712 }
1713 session_id = ((int32_t *)data)[0];
1714 snprintf(cmd, sizeof(cmd), "AT+CCHC=%" PRId32, session_id);
1715 err = at_send_command_singleline(cmd, "+CCHC", &p_response);
1716
1717 if (err < 0 || p_response == NULL || p_response->success == 0) {
1718 ALOGE("Error %d closing logical channel %d: %d",
1719 err, session_id, p_response ? p_response->success : 0);
1720 RIL_onRequestComplete(t, RIL_E_GENERIC_FAILURE, NULL, 0);
1721 at_response_free(p_response);
1722 return;
1723 }
1724
1725 RIL_onRequestComplete(t, RIL_E_SUCCESS, NULL, 0);
1726
1727 at_response_free(p_response);
1728}
1729
1730static void requestSimTransmitApduChannel(void *data,
1731 size_t datalen,
1732 RIL_Token t)
1733{
1734 ATResponse *p_response = NULL;
1735 int err;
1736 char *cmd;
1737 char *line;
1738 size_t cmd_size;
1739 RIL_SIM_IO_Response sim_response;
1740 RIL_SIM_APDU *apdu = (RIL_SIM_APDU *)data;
1741
1742 if (apdu == NULL || datalen != sizeof(RIL_SIM_APDU)) {
1743 RIL_onRequestComplete(t, RIL_E_GENERIC_FAILURE, NULL, 0);
1744 return;
1745 }
1746
1747 cmd_size = 10 + (apdu->data ? strlen(apdu->data) : 0);
Wei Wang9cec1e02017-02-08 14:37:37 -08001748 asprintf(&cmd, "AT+CGLA=%d,%zu,%02x%02x%02x%02x%02x%s",
Bjoern Johansson1fdedbd2016-10-27 16:36:29 -07001749 apdu->sessionid, cmd_size, apdu->cla, apdu->instruction,
1750 apdu->p1, apdu->p2, apdu->p3, apdu->data ? apdu->data : "");
1751
1752 err = at_send_command_singleline(cmd, "+CGLA", &p_response);
1753 free(cmd);
1754 if (err < 0 || p_response == NULL || p_response->success == 0) {
1755 ALOGE("Error %d transmitting APDU: %d",
1756 err, p_response ? p_response->success : 0);
1757 RIL_onRequestComplete(t, RIL_E_GENERIC_FAILURE, NULL, 0);
1758 at_response_free(p_response);
1759 return;
1760 }
1761
1762 line = p_response->p_intermediates->line;
1763 err = parseSimResponseLine(line, &sim_response);
1764
1765 if (err == 0) {
1766 RIL_onRequestComplete(t, RIL_E_SUCCESS,
1767 &sim_response, sizeof(sim_response));
1768 } else {
1769 ALOGE("Error %d parsing SIM response line: %s", err, line);
1770 RIL_onRequestComplete(t, RIL_E_GENERIC_FAILURE, NULL, 0);
1771 }
1772 at_response_free(p_response);
1773}
1774
Wink Savillef4c4d362009-04-02 01:37:03 -07001775static void requestSetupDataCall(void *data, size_t datalen, RIL_Token t)
The Android Open Source Project00f06fc2009-03-03 19:32:15 -08001776{
1777 const char *apn;
1778 char *cmd;
1779 int err;
1780 ATResponse *p_response = NULL;
The Android Open Source Project00f06fc2009-03-03 19:32:15 -08001781
Wink Savillef4c4d362009-04-02 01:37:03 -07001782 apn = ((const char **)data)[2];
The Android Open Source Project00f06fc2009-03-03 19:32:15 -08001783
1784#ifdef USE_TI_COMMANDS
1785 // Config for multislot class 10 (probably default anyway eh?)
1786 err = at_send_command("AT%CPRIM=\"GMM\",\"CONFIG MULTISLOT_CLASS=<10>\"",
1787 NULL);
1788
1789 err = at_send_command("AT%DATA=2,\"UART\",1,,\"SER\",\"UART\",0", NULL);
1790#endif /* USE_TI_COMMANDS */
1791
1792 int fd, qmistatus;
1793 size_t cur = 0;
1794 size_t len;
1795 ssize_t written, rlen;
1796 char status[32] = {0};
1797 int retry = 10;
Lorenzo Colitti4f81dcf2010-09-01 19:38:57 -07001798 const char *pdp_type;
The Android Open Source Project00f06fc2009-03-03 19:32:15 -08001799
Wink Saville4dcab4f2012-11-19 16:05:13 -08001800 RLOGD("requesting data connection to APN '%s'", apn);
The Android Open Source Project00f06fc2009-03-03 19:32:15 -08001801
1802 fd = open ("/dev/qmi", O_RDWR);
1803 if (fd >= 0) { /* the device doesn't exist on the emulator */
1804
Wink Saville4dcab4f2012-11-19 16:05:13 -08001805 RLOGD("opened the qmi device\n");
Lorenzo Colitti4f81dcf2010-09-01 19:38:57 -07001806 asprintf(&cmd, "up:%s", apn);
1807 len = strlen(cmd);
The Android Open Source Project00f06fc2009-03-03 19:32:15 -08001808
Lorenzo Colitti4f81dcf2010-09-01 19:38:57 -07001809 while (cur < len) {
1810 do {
1811 written = write (fd, cmd + cur, len - cur);
1812 } while (written < 0 && errno == EINTR);
The Android Open Source Project00f06fc2009-03-03 19:32:15 -08001813
Lorenzo Colitti4f81dcf2010-09-01 19:38:57 -07001814 if (written < 0) {
Wink Saville4dcab4f2012-11-19 16:05:13 -08001815 RLOGE("### ERROR writing to /dev/qmi");
The Android Open Source Project00f06fc2009-03-03 19:32:15 -08001816 close(fd);
1817 goto error;
1818 }
1819
1820 cur += written;
1821 }
1822
1823 // wait for interface to come online
1824
1825 do {
1826 sleep(1);
1827 do {
1828 rlen = read(fd, status, 31);
1829 } while (rlen < 0 && errno == EINTR);
1830
1831 if (rlen < 0) {
Wink Saville4dcab4f2012-11-19 16:05:13 -08001832 RLOGE("### ERROR reading from /dev/qmi");
The Android Open Source Project00f06fc2009-03-03 19:32:15 -08001833 close(fd);
1834 goto error;
1835 } else {
1836 status[rlen] = '\0';
Wink Saville4dcab4f2012-11-19 16:05:13 -08001837 RLOGD("### status: %s", status);
The Android Open Source Project00f06fc2009-03-03 19:32:15 -08001838 }
1839 } while (strncmp(status, "STATE=up", 8) && strcmp(status, "online") && --retry);
1840
1841 close(fd);
1842
1843 if (retry == 0) {
Wink Saville4dcab4f2012-11-19 16:05:13 -08001844 RLOGE("### Failed to get data connection up\n");
Lorenzo Colitti4f81dcf2010-09-01 19:38:57 -07001845 goto error;
1846 }
The Android Open Source Project00f06fc2009-03-03 19:32:15 -08001847
1848 qmistatus = system("netcfg rmnet0 dhcp");
1849
Wink Saville4dcab4f2012-11-19 16:05:13 -08001850 RLOGD("netcfg rmnet0 dhcp: status %d\n", qmistatus);
The Android Open Source Project00f06fc2009-03-03 19:32:15 -08001851
Lorenzo Colitti4f81dcf2010-09-01 19:38:57 -07001852 if (qmistatus < 0) goto error;
The Android Open Source Project00f06fc2009-03-03 19:32:15 -08001853
Lorenzo Colitti4f81dcf2010-09-01 19:38:57 -07001854 } else {
The Android Open Source Project00f06fc2009-03-03 19:32:15 -08001855
Lorenzo Colitti4f81dcf2010-09-01 19:38:57 -07001856 if (datalen > 6 * sizeof(char *)) {
1857 pdp_type = ((const char **)data)[6];
1858 } else {
1859 pdp_type = "IP";
1860 }
The Android Open Source Project00f06fc2009-03-03 19:32:15 -08001861
David 'Digit' Turneraf1298d2011-02-04 13:36:47 +01001862 asprintf(&cmd, "AT+CGDCONT=1,\"%s\",\"%s\",,0,0", pdp_type, apn);
Lorenzo Colitti4f81dcf2010-09-01 19:38:57 -07001863 //FIXME check for error here
1864 err = at_send_command(cmd, NULL);
1865 free(cmd);
The Android Open Source Project00f06fc2009-03-03 19:32:15 -08001866
Lorenzo Colitti4f81dcf2010-09-01 19:38:57 -07001867 // Set required QoS params to default
1868 err = at_send_command("AT+CGQREQ=1", NULL);
The Android Open Source Project00f06fc2009-03-03 19:32:15 -08001869
Lorenzo Colitti4f81dcf2010-09-01 19:38:57 -07001870 // Set minimum QoS params to default
1871 err = at_send_command("AT+CGQMIN=1", NULL);
The Android Open Source Project00f06fc2009-03-03 19:32:15 -08001872
Lorenzo Colitti4f81dcf2010-09-01 19:38:57 -07001873 // packet-domain event reporting
1874 err = at_send_command("AT+CGEREP=1,0", NULL);
The Android Open Source Project00f06fc2009-03-03 19:32:15 -08001875
Lorenzo Colitti4f81dcf2010-09-01 19:38:57 -07001876 // Hangup anything that's happening there now
1877 err = at_send_command("AT+CGACT=1,0", NULL);
The Android Open Source Project00f06fc2009-03-03 19:32:15 -08001878
Lorenzo Colitti4f81dcf2010-09-01 19:38:57 -07001879 // Start data on PDP context 1
1880 err = at_send_command("ATD*99***1#", &p_response);
1881
1882 if (err < 0 || p_response->success == 0) {
1883 goto error;
1884 }
The Android Open Source Project00f06fc2009-03-03 19:32:15 -08001885 }
1886
Wink Saville43808972011-01-13 17:39:51 -08001887 requestOrSendDataCallList(&t);
1888
The Android Open Source Project00f06fc2009-03-03 19:32:15 -08001889 at_response_free(p_response);
1890
1891 return;
1892error:
1893 RIL_onRequestComplete(t, RIL_E_GENERIC_FAILURE, NULL, 0);
1894 at_response_free(p_response);
1895
1896}
1897
Mark Salyzynba58c202014-03-12 15:20:22 -07001898static void requestSMSAcknowledge(void *data, size_t datalen __unused, RIL_Token t)
The Android Open Source Project00f06fc2009-03-03 19:32:15 -08001899{
1900 int ackSuccess;
1901 int err;
1902
1903 ackSuccess = ((int *)data)[0];
1904
1905 if (ackSuccess == 1) {
1906 err = at_send_command("AT+CNMA=1", NULL);
1907 } else if (ackSuccess == 0) {
1908 err = at_send_command("AT+CNMA=2", NULL);
1909 } else {
Wink Saville4dcab4f2012-11-19 16:05:13 -08001910 RLOGE("unsupported arg to RIL_REQUEST_SMS_ACKNOWLEDGE\n");
The Android Open Source Project00f06fc2009-03-03 19:32:15 -08001911 goto error;
1912 }
1913
1914 RIL_onRequestComplete(t, RIL_E_SUCCESS, NULL, 0);
1915error:
1916 RIL_onRequestComplete(t, RIL_E_GENERIC_FAILURE, NULL, 0);
1917
1918}
1919
Mark Salyzynba58c202014-03-12 15:20:22 -07001920static void requestSIM_IO(void *data, size_t datalen __unused, RIL_Token t)
The Android Open Source Project00f06fc2009-03-03 19:32:15 -08001921{
1922 ATResponse *p_response = NULL;
1923 RIL_SIM_IO_Response sr;
1924 int err;
1925 char *cmd = NULL;
Wink Saville2c1fb3a2011-03-19 13:42:45 -07001926 RIL_SIM_IO_v6 *p_args;
The Android Open Source Project00f06fc2009-03-03 19:32:15 -08001927 char *line;
1928
1929 memset(&sr, 0, sizeof(sr));
1930
Wink Saville2c1fb3a2011-03-19 13:42:45 -07001931 p_args = (RIL_SIM_IO_v6 *)data;
The Android Open Source Project00f06fc2009-03-03 19:32:15 -08001932
1933 /* FIXME handle pin2 */
1934
1935 if (p_args->data == NULL) {
1936 asprintf(&cmd, "AT+CRSM=%d,%d,%d,%d,%d",
1937 p_args->command, p_args->fileid,
1938 p_args->p1, p_args->p2, p_args->p3);
1939 } else {
1940 asprintf(&cmd, "AT+CRSM=%d,%d,%d,%d,%d,%s",
1941 p_args->command, p_args->fileid,
1942 p_args->p1, p_args->p2, p_args->p3, p_args->data);
1943 }
1944
1945 err = at_send_command_singleline(cmd, "+CRSM:", &p_response);
1946
1947 if (err < 0 || p_response->success == 0) {
1948 goto error;
1949 }
1950
1951 line = p_response->p_intermediates->line;
1952
Bjoern Johansson1fdedbd2016-10-27 16:36:29 -07001953 err = parseSimResponseLine(line, &sr);
1954 if (err < 0) {
1955 goto error;
The Android Open Source Project00f06fc2009-03-03 19:32:15 -08001956 }
1957
1958 RIL_onRequestComplete(t, RIL_E_SUCCESS, &sr, sizeof(sr));
1959 at_response_free(p_response);
1960 free(cmd);
1961
1962 return;
1963error:
1964 RIL_onRequestComplete(t, RIL_E_GENERIC_FAILURE, NULL, 0);
1965 at_response_free(p_response);
1966 free(cmd);
1967
1968}
1969
1970static void requestEnterSimPin(void* data, size_t datalen, RIL_Token t)
1971{
1972 ATResponse *p_response = NULL;
1973 int err;
1974 char* cmd = NULL;
1975 const char** strings = (const char**)data;;
1976
1977 if ( datalen == sizeof(char*) ) {
1978 asprintf(&cmd, "AT+CPIN=%s", strings[0]);
1979 } else if ( datalen == 2*sizeof(char*) ) {
1980 asprintf(&cmd, "AT+CPIN=%s,%s", strings[0], strings[1]);
1981 } else
1982 goto error;
1983
1984 err = at_send_command_singleline(cmd, "+CPIN:", &p_response);
1985 free(cmd);
1986
1987 if (err < 0 || p_response->success == 0) {
1988error:
1989 RIL_onRequestComplete(t, RIL_E_PASSWORD_INCORRECT, NULL, 0);
1990 } else {
1991 RIL_onRequestComplete(t, RIL_E_SUCCESS, NULL, 0);
1992 }
1993 at_response_free(p_response);
1994}
1995
1996
Mark Salyzynba58c202014-03-12 15:20:22 -07001997static void requestSendUSSD(void *data, size_t datalen __unused, RIL_Token t)
The Android Open Source Project00f06fc2009-03-03 19:32:15 -08001998{
1999 const char *ussdRequest;
2000
2001 ussdRequest = (char *)(data);
2002
2003
2004 RIL_onRequestComplete(t, RIL_E_REQUEST_NOT_SUPPORTED, NULL, 0);
2005
2006// @@@ TODO
2007
2008}
2009
Mark Salyzynba58c202014-03-12 15:20:22 -07002010static void requestExitEmergencyMode(void *data __unused, size_t datalen __unused, RIL_Token t)
Jaime A Lopez-Sollanoe9645042012-08-29 07:27:27 -07002011{
2012 int err;
2013 ATResponse *p_response = NULL;
2014
2015 err = at_send_command("AT+WSOS=0", &p_response);
2016
2017 if (err < 0 || p_response->success == 0) {
2018 RIL_onRequestComplete(t, RIL_E_GENERIC_FAILURE, NULL, 0);
2019 return;
2020 }
2021
2022 RIL_onRequestComplete(t, RIL_E_SUCCESS, NULL, 0);
2023}
2024
2025// TODO: Use all radio types
2026static int techFromModemType(int mdmtype)
2027{
2028 int ret = -1;
2029 switch (1 << mdmtype) {
2030 case MDM_CDMA:
2031 ret = RADIO_TECH_1xRTT;
2032 break;
2033 case MDM_EVDO:
2034 ret = RADIO_TECH_EVDO_A;
2035 break;
2036 case MDM_GSM:
2037 ret = RADIO_TECH_GPRS;
2038 break;
2039 case MDM_WCDMA:
2040 ret = RADIO_TECH_HSPA;
2041 break;
2042 case MDM_LTE:
2043 ret = RADIO_TECH_LTE;
2044 break;
2045 }
2046 return ret;
2047}
The Android Open Source Project00f06fc2009-03-03 19:32:15 -08002048
Mark Salyzynba58c202014-03-12 15:20:22 -07002049static void requestGetCellInfoList(void *data __unused, size_t datalen __unused, RIL_Token t)
Wink Saville8a9e0212013-04-09 12:11:38 -07002050{
2051 uint64_t curTime = ril_nano_time();
2052 RIL_CellInfo ci[1] =
2053 {
2054 { // ci[0]
2055 1, // cellInfoType
2056 1, // registered
Sanket Padawef0c8ca72016-06-30 15:01:08 -07002057 RIL_TIMESTAMP_TYPE_MODEM,
Wink Saville8a9e0212013-04-09 12:11:38 -07002058 curTime - 1000, // Fake some time in the past
2059 { // union CellInfo
2060 { // RIL_CellInfoGsm gsm
2061 { // gsm.cellIdneityGsm
2062 s_mcc, // mcc
2063 s_mnc, // mnc
2064 s_lac, // lac
2065 s_cid, // cid
Wink Saville8a9e0212013-04-09 12:11:38 -07002066 },
2067 { // gsm.signalStrengthGsm
2068 10, // signalStrength
2069 0 // bitErrorRate
2070 }
2071 }
2072 }
2073 }
2074 };
2075
2076 RIL_onRequestComplete(t, RIL_E_SUCCESS, ci, sizeof(ci));
2077}
2078
2079
Sanket Padawef0c8ca72016-06-30 15:01:08 -07002080static void requestSetCellInfoListRate(void *data, size_t datalen __unused, RIL_Token t)
Wink Saville8a9e0212013-04-09 12:11:38 -07002081{
2082 // For now we'll save the rate but no RIL_UNSOL_CELL_INFO_LIST messages
2083 // will be sent.
2084 assert (datalen == sizeof(int));
2085 s_cell_info_rate_ms = ((int *)data)[0];
2086
2087 RIL_onRequestComplete(t, RIL_E_SUCCESS, NULL, 0);
2088}
2089
Etan Cohend3652192014-06-20 08:28:44 -07002090static void requestGetHardwareConfig(void *data, size_t datalen, RIL_Token t)
2091{
2092 // TODO - hook this up with real query/info from radio.
2093
2094 RIL_HardwareConfig hwCfg;
2095
2096 RIL_UNUSED_PARM(data);
2097 RIL_UNUSED_PARM(datalen);
2098
2099 hwCfg.type = -1;
2100
2101 RIL_onRequestComplete(t, RIL_E_SUCCESS, &hwCfg, sizeof(hwCfg));
2102}
2103
2104
The Android Open Source Project00f06fc2009-03-03 19:32:15 -08002105/*** Callback methods from the RIL library to us ***/
2106
2107/**
2108 * Call from RIL to us to make a RIL_REQUEST
2109 *
2110 * Must be completed with a call to RIL_onRequestComplete()
2111 *
2112 * RIL_onRequestComplete() may be called from any thread, before or after
2113 * this function returns.
2114 *
Weilun Du9f471e22017-02-07 10:47:19 -08002115 * Because onRequest function could be called from multiple different thread,
2116 * we must ensure that the underlying at_send_command_* function
2117 * is atomic.
The Android Open Source Project00f06fc2009-03-03 19:32:15 -08002118 */
2119static void
2120onRequest (int request, void *data, size_t datalen, RIL_Token t)
2121{
2122 ATResponse *p_response;
2123 int err;
2124
Wink Saville4dcab4f2012-11-19 16:05:13 -08002125 RLOGD("onRequest: %s", requestToString(request));
The Android Open Source Project00f06fc2009-03-03 19:32:15 -08002126
2127 /* Ignore all requests except RIL_REQUEST_GET_SIM_STATUS
2128 * when RADIO_STATE_UNAVAILABLE.
2129 */
2130 if (sState == RADIO_STATE_UNAVAILABLE
2131 && request != RIL_REQUEST_GET_SIM_STATUS
2132 ) {
2133 RIL_onRequestComplete(t, RIL_E_RADIO_NOT_AVAILABLE, NULL, 0);
2134 return;
2135 }
2136
2137 /* Ignore all non-power requests when RADIO_STATE_OFF
2138 * (except RIL_REQUEST_GET_SIM_STATUS)
2139 */
2140 if (sState == RADIO_STATE_OFF
2141 && !(request == RIL_REQUEST_RADIO_POWER
2142 || request == RIL_REQUEST_GET_SIM_STATUS)
2143 ) {
2144 RIL_onRequestComplete(t, RIL_E_RADIO_NOT_AVAILABLE, NULL, 0);
2145 return;
2146 }
2147
2148 switch (request) {
2149 case RIL_REQUEST_GET_SIM_STATUS: {
Wink Saville2c1fb3a2011-03-19 13:42:45 -07002150 RIL_CardStatus_v6 *p_card_status;
Wink Savillef6aa7c12009-04-30 14:20:52 -07002151 char *p_buffer;
2152 int buffer_size;
The Android Open Source Project00f06fc2009-03-03 19:32:15 -08002153
Wink Savillef6aa7c12009-04-30 14:20:52 -07002154 int result = getCardStatus(&p_card_status);
2155 if (result == RIL_E_SUCCESS) {
2156 p_buffer = (char *)p_card_status;
2157 buffer_size = sizeof(*p_card_status);
2158 } else {
2159 p_buffer = NULL;
2160 buffer_size = 0;
2161 }
2162 RIL_onRequestComplete(t, result, p_buffer, buffer_size);
2163 freeCardStatus(p_card_status);
The Android Open Source Project00f06fc2009-03-03 19:32:15 -08002164 break;
2165 }
2166 case RIL_REQUEST_GET_CURRENT_CALLS:
2167 requestGetCurrentCalls(data, datalen, t);
2168 break;
2169 case RIL_REQUEST_DIAL:
2170 requestDial(data, datalen, t);
2171 break;
2172 case RIL_REQUEST_HANGUP:
2173 requestHangup(data, datalen, t);
2174 break;
2175 case RIL_REQUEST_HANGUP_WAITING_OR_BACKGROUND:
2176 // 3GPP 22.030 6.5.5
2177 // "Releases all held calls or sets User Determined User Busy
2178 // (UDUB) for a waiting call."
2179 at_send_command("AT+CHLD=0", NULL);
2180
2181 /* success or failure is ignored by the upper layer here.
2182 it will call GET_CURRENT_CALLS and determine success that way */
2183 RIL_onRequestComplete(t, RIL_E_SUCCESS, NULL, 0);
2184 break;
2185 case RIL_REQUEST_HANGUP_FOREGROUND_RESUME_BACKGROUND:
2186 // 3GPP 22.030 6.5.5
2187 // "Releases all active calls (if any exist) and accepts
2188 // the other (held or waiting) call."
2189 at_send_command("AT+CHLD=1", NULL);
2190
2191 /* success or failure is ignored by the upper layer here.
2192 it will call GET_CURRENT_CALLS and determine success that way */
2193 RIL_onRequestComplete(t, RIL_E_SUCCESS, NULL, 0);
2194 break;
2195 case RIL_REQUEST_SWITCH_WAITING_OR_HOLDING_AND_ACTIVE:
2196 // 3GPP 22.030 6.5.5
2197 // "Places all active calls (if any exist) on hold and accepts
2198 // the other (held or waiting) call."
2199 at_send_command("AT+CHLD=2", NULL);
2200
2201#ifdef WORKAROUND_ERRONEOUS_ANSWER
2202 s_expectAnswer = 1;
2203#endif /* WORKAROUND_ERRONEOUS_ANSWER */
2204
2205 /* success or failure is ignored by the upper layer here.
2206 it will call GET_CURRENT_CALLS and determine success that way */
2207 RIL_onRequestComplete(t, RIL_E_SUCCESS, NULL, 0);
2208 break;
2209 case RIL_REQUEST_ANSWER:
2210 at_send_command("ATA", NULL);
2211
2212#ifdef WORKAROUND_ERRONEOUS_ANSWER
2213 s_expectAnswer = 1;
2214#endif /* WORKAROUND_ERRONEOUS_ANSWER */
2215
2216 /* success or failure is ignored by the upper layer here.
2217 it will call GET_CURRENT_CALLS and determine success that way */
2218 RIL_onRequestComplete(t, RIL_E_SUCCESS, NULL, 0);
2219 break;
2220 case RIL_REQUEST_CONFERENCE:
2221 // 3GPP 22.030 6.5.5
2222 // "Adds a held call to the conversation"
2223 at_send_command("AT+CHLD=3", NULL);
2224
2225 /* success or failure is ignored by the upper layer here.
2226 it will call GET_CURRENT_CALLS and determine success that way */
2227 RIL_onRequestComplete(t, RIL_E_SUCCESS, NULL, 0);
2228 break;
2229 case RIL_REQUEST_UDUB:
2230 /* user determined user busy */
2231 /* sometimes used: ATH */
2232 at_send_command("ATH", NULL);
2233
2234 /* success or failure is ignored by the upper layer here.
2235 it will call GET_CURRENT_CALLS and determine success that way */
2236 RIL_onRequestComplete(t, RIL_E_SUCCESS, NULL, 0);
2237 break;
2238
2239 case RIL_REQUEST_SEPARATE_CONNECTION:
2240 {
2241 char cmd[12];
2242 int party = ((int*)data)[0];
2243
2244 // Make sure that party is in a valid range.
2245 // (Note: The Telephony middle layer imposes a range of 1 to 7.
2246 // It's sufficient for us to just make sure it's single digit.)
2247 if (party > 0 && party < 10) {
2248 sprintf(cmd, "AT+CHLD=2%d", party);
2249 at_send_command(cmd, NULL);
2250 RIL_onRequestComplete(t, RIL_E_SUCCESS, NULL, 0);
2251 } else {
2252 RIL_onRequestComplete(t, RIL_E_GENERIC_FAILURE, NULL, 0);
2253 }
2254 }
2255 break;
2256
2257 case RIL_REQUEST_SIGNAL_STRENGTH:
2258 requestSignalStrength(data, datalen, t);
2259 break;
Wink Saville2c1fb3a2011-03-19 13:42:45 -07002260 case RIL_REQUEST_VOICE_REGISTRATION_STATE:
2261 case RIL_REQUEST_DATA_REGISTRATION_STATE:
The Android Open Source Project00f06fc2009-03-03 19:32:15 -08002262 requestRegistrationState(request, data, datalen, t);
2263 break;
2264 case RIL_REQUEST_OPERATOR:
2265 requestOperator(data, datalen, t);
2266 break;
2267 case RIL_REQUEST_RADIO_POWER:
2268 requestRadioPower(data, datalen, t);
2269 break;
2270 case RIL_REQUEST_DTMF: {
2271 char c = ((char *)data)[0];
2272 char *cmd;
2273 asprintf(&cmd, "AT+VTS=%c", (int)c);
2274 at_send_command(cmd, NULL);
2275 free(cmd);
2276 RIL_onRequestComplete(t, RIL_E_SUCCESS, NULL, 0);
2277 break;
2278 }
2279 case RIL_REQUEST_SEND_SMS:
Chaitanya Saggurthi33bbe432013-09-24 16:16:21 +05302280 case RIL_REQUEST_SEND_SMS_EXPECT_MORE:
The Android Open Source Project00f06fc2009-03-03 19:32:15 -08002281 requestSendSMS(data, datalen, t);
2282 break;
Jaime A Lopez-Sollanoe9645042012-08-29 07:27:27 -07002283 case RIL_REQUEST_CDMA_SEND_SMS:
2284 requestCdmaSendSMS(data, datalen, t);
2285 break;
Sukanya Rajkhowaa18b9d12013-09-10 12:30:13 -07002286 case RIL_REQUEST_IMS_SEND_SMS:
2287 requestImsSendSMS(data, datalen, t);
2288 break;
Bjoern Johansson1fdedbd2016-10-27 16:36:29 -07002289 case RIL_REQUEST_SIM_OPEN_CHANNEL:
2290 requestSimOpenChannel(data, datalen, t);
2291 break;
2292 case RIL_REQUEST_SIM_CLOSE_CHANNEL:
2293 requestSimCloseChannel(data, datalen, t);
2294 break;
2295 case RIL_REQUEST_SIM_TRANSMIT_APDU_CHANNEL:
2296 requestSimTransmitApduChannel(data, datalen, t);
2297 break;
Wink Savillef4c4d362009-04-02 01:37:03 -07002298 case RIL_REQUEST_SETUP_DATA_CALL:
2299 requestSetupDataCall(data, datalen, t);
The Android Open Source Project00f06fc2009-03-03 19:32:15 -08002300 break;
2301 case RIL_REQUEST_SMS_ACKNOWLEDGE:
2302 requestSMSAcknowledge(data, datalen, t);
2303 break;
2304
2305 case RIL_REQUEST_GET_IMSI:
2306 p_response = NULL;
2307 err = at_send_command_numeric("AT+CIMI", &p_response);
2308
2309 if (err < 0 || p_response->success == 0) {
2310 RIL_onRequestComplete(t, RIL_E_GENERIC_FAILURE, NULL, 0);
2311 } else {
2312 RIL_onRequestComplete(t, RIL_E_SUCCESS,
2313 p_response->p_intermediates->line, sizeof(char *));
2314 }
2315 at_response_free(p_response);
2316 break;
2317
2318 case RIL_REQUEST_GET_IMEI:
2319 p_response = NULL;
2320 err = at_send_command_numeric("AT+CGSN", &p_response);
2321
2322 if (err < 0 || p_response->success == 0) {
2323 RIL_onRequestComplete(t, RIL_E_GENERIC_FAILURE, NULL, 0);
2324 } else {
2325 RIL_onRequestComplete(t, RIL_E_SUCCESS,
2326 p_response->p_intermediates->line, sizeof(char *));
2327 }
2328 at_response_free(p_response);
2329 break;
2330
2331 case RIL_REQUEST_SIM_IO:
2332 requestSIM_IO(data,datalen,t);
2333 break;
2334
2335 case RIL_REQUEST_SEND_USSD:
2336 requestSendUSSD(data, datalen, t);
2337 break;
2338
2339 case RIL_REQUEST_CANCEL_USSD:
2340 p_response = NULL;
2341 err = at_send_command_numeric("AT+CUSD=2", &p_response);
2342
2343 if (err < 0 || p_response->success == 0) {
2344 RIL_onRequestComplete(t, RIL_E_GENERIC_FAILURE, NULL, 0);
2345 } else {
2346 RIL_onRequestComplete(t, RIL_E_SUCCESS,
2347 p_response->p_intermediates->line, sizeof(char *));
2348 }
2349 at_response_free(p_response);
2350 break;
2351
2352 case RIL_REQUEST_SET_NETWORK_SELECTION_AUTOMATIC:
2353 at_send_command("AT+COPS=0", NULL);
2354 break;
2355
Wink Savillef4c4d362009-04-02 01:37:03 -07002356 case RIL_REQUEST_DATA_CALL_LIST:
2357 requestDataCallList(data, datalen, t);
The Android Open Source Project00f06fc2009-03-03 19:32:15 -08002358 break;
2359
2360 case RIL_REQUEST_QUERY_NETWORK_SELECTION_MODE:
2361 requestQueryNetworkSelectionMode(data, datalen, t);
2362 break;
2363
2364 case RIL_REQUEST_OEM_HOOK_RAW:
2365 // echo back data
2366 RIL_onRequestComplete(t, RIL_E_SUCCESS, data, datalen);
2367 break;
2368
2369
2370 case RIL_REQUEST_OEM_HOOK_STRINGS: {
2371 int i;
2372 const char ** cur;
2373
Wink Saville4dcab4f2012-11-19 16:05:13 -08002374 RLOGD("got OEM_HOOK_STRINGS: 0x%8p %lu", data, (long)datalen);
The Android Open Source Project00f06fc2009-03-03 19:32:15 -08002375
2376
2377 for (i = (datalen / sizeof (char *)), cur = (const char **)data ;
2378 i > 0 ; cur++, i --) {
Wink Saville4dcab4f2012-11-19 16:05:13 -08002379 RLOGD("> '%s'", *cur);
The Android Open Source Project00f06fc2009-03-03 19:32:15 -08002380 }
2381
2382 // echo back strings
2383 RIL_onRequestComplete(t, RIL_E_SUCCESS, data, datalen);
2384 break;
2385 }
2386
2387 case RIL_REQUEST_WRITE_SMS_TO_SIM:
2388 requestWriteSmsToSim(data, datalen, t);
2389 break;
2390
2391 case RIL_REQUEST_DELETE_SMS_ON_SIM: {
2392 char * cmd;
2393 p_response = NULL;
2394 asprintf(&cmd, "AT+CMGD=%d", ((int *)data)[0]);
2395 err = at_send_command(cmd, &p_response);
2396 free(cmd);
2397 if (err < 0 || p_response->success == 0) {
2398 RIL_onRequestComplete(t, RIL_E_GENERIC_FAILURE, NULL, 0);
2399 } else {
2400 RIL_onRequestComplete(t, RIL_E_SUCCESS, NULL, 0);
2401 }
2402 at_response_free(p_response);
2403 break;
2404 }
2405
2406 case RIL_REQUEST_ENTER_SIM_PIN:
2407 case RIL_REQUEST_ENTER_SIM_PUK:
2408 case RIL_REQUEST_ENTER_SIM_PIN2:
2409 case RIL_REQUEST_ENTER_SIM_PUK2:
2410 case RIL_REQUEST_CHANGE_SIM_PIN:
2411 case RIL_REQUEST_CHANGE_SIM_PIN2:
2412 requestEnterSimPin(data, datalen, t);
2413 break;
2414
Sukanya Rajkhowaa18b9d12013-09-10 12:30:13 -07002415 case RIL_REQUEST_IMS_REGISTRATION_STATE: {
2416 int reply[2];
2417 //0==unregistered, 1==registered
2418 reply[0] = s_ims_registered;
2419
2420 //to be used when changed to include service supporated info
2421 //reply[1] = s_ims_services;
2422
2423 // FORMAT_3GPP(1) vs FORMAT_3GPP2(2);
2424 reply[1] = s_ims_format;
2425
2426 RLOGD("IMS_REGISTRATION=%d, format=%d ",
2427 reply[0], reply[1]);
2428 if (reply[1] != -1) {
2429 RIL_onRequestComplete(t, RIL_E_SUCCESS, reply, sizeof(reply));
2430 } else {
2431 RIL_onRequestComplete(t, RIL_E_GENERIC_FAILURE, NULL, 0);
2432 }
2433 break;
2434 }
2435
Jaime A Lopez-Sollanoe9645042012-08-29 07:27:27 -07002436 case RIL_REQUEST_VOICE_RADIO_TECH:
2437 {
2438 int tech = techFromModemType(TECH(sMdmInfo));
2439 if (tech < 0 )
2440 RIL_onRequestComplete(t, RIL_E_GENERIC_FAILURE, NULL, 0);
2441 else
2442 RIL_onRequestComplete(t, RIL_E_SUCCESS, &tech, sizeof(tech));
2443 }
2444 break;
2445 case RIL_REQUEST_SET_PREFERRED_NETWORK_TYPE:
2446 requestSetPreferredNetworkType(request, data, datalen, t);
2447 break;
2448
2449 case RIL_REQUEST_GET_PREFERRED_NETWORK_TYPE:
2450 requestGetPreferredNetworkType(request, data, datalen, t);
2451 break;
2452
Jun Tian58027012013-07-30 11:07:22 +08002453 case RIL_REQUEST_GET_CELL_INFO_LIST:
2454 requestGetCellInfoList(data, datalen, t);
2455 break;
2456
2457 case RIL_REQUEST_SET_UNSOL_CELL_INFO_LIST_RATE:
2458 requestSetCellInfoListRate(data, datalen, t);
2459 break;
2460
Etan Cohend3652192014-06-20 08:28:44 -07002461 case RIL_REQUEST_GET_HARDWARE_CONFIG:
2462 requestGetHardwareConfig(data, datalen, t);
2463 break;
2464
Naveen Kallaa65a16a2014-07-31 16:48:31 -07002465 case RIL_REQUEST_SHUTDOWN:
2466 requestShutdown(t);
2467 break;
2468
Jaime A Lopez-Sollanoe9645042012-08-29 07:27:27 -07002469 /* CDMA Specific Requests */
2470 case RIL_REQUEST_BASEBAND_VERSION:
2471 if (TECH_BIT(sMdmInfo) == MDM_CDMA) {
2472 requestCdmaBaseBandVersion(request, data, datalen, t);
2473 break;
2474 } // Fall-through if tech is not cdma
2475
2476 case RIL_REQUEST_DEVICE_IDENTITY:
2477 if (TECH_BIT(sMdmInfo) == MDM_CDMA) {
2478 requestCdmaDeviceIdentity(request, data, datalen, t);
2479 break;
2480 } // Fall-through if tech is not cdma
2481
2482 case RIL_REQUEST_CDMA_SUBSCRIPTION:
2483 if (TECH_BIT(sMdmInfo) == MDM_CDMA) {
2484 requestCdmaSubscription(request, data, datalen, t);
2485 break;
2486 } // Fall-through if tech is not cdma
2487
2488 case RIL_REQUEST_CDMA_SET_SUBSCRIPTION_SOURCE:
2489 if (TECH_BIT(sMdmInfo) == MDM_CDMA) {
2490 requestCdmaSetSubscriptionSource(request, data, datalen, t);
2491 break;
2492 } // Fall-through if tech is not cdma
2493
2494 case RIL_REQUEST_CDMA_GET_SUBSCRIPTION_SOURCE:
2495 if (TECH_BIT(sMdmInfo) == MDM_CDMA) {
2496 requestCdmaGetSubscriptionSource(request, data, datalen, t);
2497 break;
2498 } // Fall-through if tech is not cdma
2499
2500 case RIL_REQUEST_CDMA_QUERY_ROAMING_PREFERENCE:
2501 if (TECH_BIT(sMdmInfo) == MDM_CDMA) {
2502 requestCdmaGetRoamingPreference(request, data, datalen, t);
2503 break;
2504 } // Fall-through if tech is not cdma
2505
2506 case RIL_REQUEST_CDMA_SET_ROAMING_PREFERENCE:
2507 if (TECH_BIT(sMdmInfo) == MDM_CDMA) {
2508 requestCdmaSetRoamingPreference(request, data, datalen, t);
2509 break;
2510 } // Fall-through if tech is not cdma
2511
2512 case RIL_REQUEST_EXIT_EMERGENCY_CALLBACK_MODE:
2513 if (TECH_BIT(sMdmInfo) == MDM_CDMA) {
2514 requestExitEmergencyMode(data, datalen, t);
2515 break;
2516 } // Fall-through if tech is not cdma
2517
The Android Open Source Project00f06fc2009-03-03 19:32:15 -08002518 default:
Wink Saville4dcab4f2012-11-19 16:05:13 -08002519 RLOGD("Request not supported. Tech: %d",TECH(sMdmInfo));
The Android Open Source Project00f06fc2009-03-03 19:32:15 -08002520 RIL_onRequestComplete(t, RIL_E_REQUEST_NOT_SUPPORTED, NULL, 0);
2521 break;
2522 }
2523}
2524
2525/**
2526 * Synchronous call from the RIL to us to return current radio state.
2527 * RADIO_STATE_UNAVAILABLE should be the initial state.
2528 */
2529static RIL_RadioState
2530currentState()
2531{
2532 return sState;
2533}
2534/**
2535 * Call from RIL to us to find out whether a specific request code
2536 * is supported by this implementation.
2537 *
2538 * Return 1 for "supported" and 0 for "unsupported"
2539 */
2540
2541static int
Mark Salyzynba58c202014-03-12 15:20:22 -07002542onSupports (int requestCode __unused)
The Android Open Source Project00f06fc2009-03-03 19:32:15 -08002543{
2544 //@@@ todo
2545
2546 return 1;
2547}
2548
Mark Salyzynba58c202014-03-12 15:20:22 -07002549static void onCancel (RIL_Token t __unused)
The Android Open Source Project00f06fc2009-03-03 19:32:15 -08002550{
2551 //@@@todo
2552
2553}
2554
2555static const char * getVersion(void)
2556{
2557 return "android reference-ril 1.0";
2558}
2559
2560static void
Jaime A Lopez-Sollanoe9645042012-08-29 07:27:27 -07002561setRadioTechnology(ModemInfo *mdm, int newtech)
2562{
Wink Saville4dcab4f2012-11-19 16:05:13 -08002563 RLOGD("setRadioTechnology(%d)", newtech);
Jaime A Lopez-Sollanoe9645042012-08-29 07:27:27 -07002564
2565 int oldtech = TECH(mdm);
2566
2567 if (newtech != oldtech) {
Wink Saville4dcab4f2012-11-19 16:05:13 -08002568 RLOGD("Tech change (%d => %d)", oldtech, newtech);
Jaime A Lopez-Sollanoe9645042012-08-29 07:27:27 -07002569 TECH(mdm) = newtech;
2570 if (techFromModemType(newtech) != techFromModemType(oldtech)) {
2571 int tech = techFromModemType(TECH(sMdmInfo));
2572 if (tech > 0 ) {
2573 RIL_onUnsolicitedResponse(RIL_UNSOL_VOICE_RADIO_TECH_CHANGED,
2574 &tech, sizeof(tech));
2575 }
2576 }
2577 }
2578}
2579
2580static void
The Android Open Source Project00f06fc2009-03-03 19:32:15 -08002581setRadioState(RIL_RadioState newState)
2582{
Wink Saville4dcab4f2012-11-19 16:05:13 -08002583 RLOGD("setRadioState(%d)", newState);
The Android Open Source Project00f06fc2009-03-03 19:32:15 -08002584 RIL_RadioState oldState;
2585
2586 pthread_mutex_lock(&s_state_mutex);
2587
2588 oldState = sState;
2589
2590 if (s_closed > 0) {
2591 // If we're closed, the only reasonable state is
2592 // RADIO_STATE_UNAVAILABLE
2593 // This is here because things on the main thread
2594 // may attempt to change the radio state after the closed
2595 // event happened in another thread
2596 newState = RADIO_STATE_UNAVAILABLE;
2597 }
2598
2599 if (sState != newState || s_closed > 0) {
2600 sState = newState;
2601
2602 pthread_cond_broadcast (&s_state_cond);
2603 }
2604
2605 pthread_mutex_unlock(&s_state_mutex);
2606
2607
2608 /* do these outside of the mutex */
2609 if (sState != oldState) {
2610 RIL_onUnsolicitedResponse (RIL_UNSOL_RESPONSE_RADIO_STATE_CHANGED,
2611 NULL, 0);
Alex Yakavenka81d14852013-12-04 13:54:37 -08002612 // Sim state can change as result of radio state change
2613 RIL_onUnsolicitedResponse (RIL_UNSOL_RESPONSE_SIM_STATUS_CHANGED,
2614 NULL, 0);
The Android Open Source Project00f06fc2009-03-03 19:32:15 -08002615
2616 /* FIXME onSimReady() and onRadioPowerOn() cannot be called
2617 * from the AT reader thread
2618 * Currently, this doesn't happen, but if that changes then these
2619 * will need to be dispatched on the request thread
2620 */
Jaime A Lopez-Sollanoe9645042012-08-29 07:27:27 -07002621 if (sState == RADIO_STATE_ON) {
The Android Open Source Project00f06fc2009-03-03 19:32:15 -08002622 onRadioPowerOn();
2623 }
2624 }
2625}
2626
Jaime A Lopez-Sollanoe9645042012-08-29 07:27:27 -07002627/** Returns RUIM_NOT_READY on error */
2628static SIM_Status
2629getRUIMStatus()
2630{
2631 ATResponse *p_response = NULL;
2632 int err;
2633 int ret;
2634 char *cpinLine;
2635 char *cpinResult;
2636
2637 if (sState == RADIO_STATE_OFF || sState == RADIO_STATE_UNAVAILABLE) {
2638 ret = SIM_NOT_READY;
2639 goto done;
2640 }
2641
2642 err = at_send_command_singleline("AT+CPIN?", "+CPIN:", &p_response);
2643
2644 if (err != 0) {
2645 ret = SIM_NOT_READY;
2646 goto done;
2647 }
2648
2649 switch (at_get_cme_error(p_response)) {
2650 case CME_SUCCESS:
2651 break;
2652
2653 case CME_SIM_NOT_INSERTED:
2654 ret = SIM_ABSENT;
2655 goto done;
2656
2657 default:
2658 ret = SIM_NOT_READY;
2659 goto done;
2660 }
2661
2662 /* CPIN? has succeeded, now look at the result */
2663
2664 cpinLine = p_response->p_intermediates->line;
2665 err = at_tok_start (&cpinLine);
2666
2667 if (err < 0) {
2668 ret = SIM_NOT_READY;
2669 goto done;
2670 }
2671
2672 err = at_tok_nextstr(&cpinLine, &cpinResult);
2673
2674 if (err < 0) {
2675 ret = SIM_NOT_READY;
2676 goto done;
2677 }
2678
2679 if (0 == strcmp (cpinResult, "SIM PIN")) {
2680 ret = SIM_PIN;
2681 goto done;
2682 } else if (0 == strcmp (cpinResult, "SIM PUK")) {
2683 ret = SIM_PUK;
2684 goto done;
2685 } else if (0 == strcmp (cpinResult, "PH-NET PIN")) {
2686 return SIM_NETWORK_PERSONALIZATION;
2687 } else if (0 != strcmp (cpinResult, "READY")) {
2688 /* we're treating unsupported lock types as "sim absent" */
2689 ret = SIM_ABSENT;
2690 goto done;
2691 }
2692
2693 at_response_free(p_response);
2694 p_response = NULL;
2695 cpinResult = NULL;
2696
2697 ret = SIM_READY;
2698
2699done:
2700 at_response_free(p_response);
2701 return ret;
2702}
2703
John Wang309ac292009-07-30 14:53:23 -07002704/** Returns SIM_NOT_READY on error */
David 'Digit' Turneraf1298d2011-02-04 13:36:47 +01002705static SIM_Status
The Android Open Source Project00f06fc2009-03-03 19:32:15 -08002706getSIMStatus()
2707{
2708 ATResponse *p_response = NULL;
2709 int err;
2710 int ret;
2711 char *cpinLine;
2712 char *cpinResult;
2713
Wink Saville4dcab4f2012-11-19 16:05:13 -08002714 RLOGD("getSIMStatus(). sState: %d",sState);
The Android Open Source Project00f06fc2009-03-03 19:32:15 -08002715 if (sState == RADIO_STATE_OFF || sState == RADIO_STATE_UNAVAILABLE) {
John Wang309ac292009-07-30 14:53:23 -07002716 ret = SIM_NOT_READY;
The Android Open Source Project00f06fc2009-03-03 19:32:15 -08002717 goto done;
2718 }
2719
2720 err = at_send_command_singleline("AT+CPIN?", "+CPIN:", &p_response);
2721
2722 if (err != 0) {
John Wang309ac292009-07-30 14:53:23 -07002723 ret = SIM_NOT_READY;
The Android Open Source Project00f06fc2009-03-03 19:32:15 -08002724 goto done;
2725 }
2726
2727 switch (at_get_cme_error(p_response)) {
2728 case CME_SUCCESS:
2729 break;
2730
2731 case CME_SIM_NOT_INSERTED:
John Wang309ac292009-07-30 14:53:23 -07002732 ret = SIM_ABSENT;
The Android Open Source Project00f06fc2009-03-03 19:32:15 -08002733 goto done;
2734
2735 default:
John Wang309ac292009-07-30 14:53:23 -07002736 ret = SIM_NOT_READY;
The Android Open Source Project00f06fc2009-03-03 19:32:15 -08002737 goto done;
2738 }
2739
2740 /* CPIN? has succeeded, now look at the result */
2741
2742 cpinLine = p_response->p_intermediates->line;
2743 err = at_tok_start (&cpinLine);
2744
2745 if (err < 0) {
John Wang309ac292009-07-30 14:53:23 -07002746 ret = SIM_NOT_READY;
The Android Open Source Project00f06fc2009-03-03 19:32:15 -08002747 goto done;
2748 }
2749
2750 err = at_tok_nextstr(&cpinLine, &cpinResult);
2751
2752 if (err < 0) {
John Wang309ac292009-07-30 14:53:23 -07002753 ret = SIM_NOT_READY;
The Android Open Source Project00f06fc2009-03-03 19:32:15 -08002754 goto done;
2755 }
2756
2757 if (0 == strcmp (cpinResult, "SIM PIN")) {
John Wang309ac292009-07-30 14:53:23 -07002758 ret = SIM_PIN;
The Android Open Source Project00f06fc2009-03-03 19:32:15 -08002759 goto done;
2760 } else if (0 == strcmp (cpinResult, "SIM PUK")) {
John Wang309ac292009-07-30 14:53:23 -07002761 ret = SIM_PUK;
The Android Open Source Project00f06fc2009-03-03 19:32:15 -08002762 goto done;
2763 } else if (0 == strcmp (cpinResult, "PH-NET PIN")) {
John Wang309ac292009-07-30 14:53:23 -07002764 return SIM_NETWORK_PERSONALIZATION;
The Android Open Source Project00f06fc2009-03-03 19:32:15 -08002765 } else if (0 != strcmp (cpinResult, "READY")) {
2766 /* we're treating unsupported lock types as "sim absent" */
John Wang309ac292009-07-30 14:53:23 -07002767 ret = SIM_ABSENT;
The Android Open Source Project00f06fc2009-03-03 19:32:15 -08002768 goto done;
2769 }
2770
2771 at_response_free(p_response);
2772 p_response = NULL;
2773 cpinResult = NULL;
2774
John Wang309ac292009-07-30 14:53:23 -07002775 ret = SIM_READY;
The Android Open Source Project00f06fc2009-03-03 19:32:15 -08002776
2777done:
2778 at_response_free(p_response);
2779 return ret;
2780}
2781
2782
2783/**
Wink Savillef6aa7c12009-04-30 14:20:52 -07002784 * Get the current card status.
2785 *
2786 * This must be freed using freeCardStatus.
2787 * @return: On success returns RIL_E_SUCCESS
2788 */
Wink Saville2c1fb3a2011-03-19 13:42:45 -07002789static int getCardStatus(RIL_CardStatus_v6 **pp_card_status) {
Wink Savillef6aa7c12009-04-30 14:20:52 -07002790 static RIL_AppStatus app_status_array[] = {
John Wang309ac292009-07-30 14:53:23 -07002791 // SIM_ABSENT = 0
Wink Savillef6aa7c12009-04-30 14:20:52 -07002792 { RIL_APPTYPE_UNKNOWN, RIL_APPSTATE_UNKNOWN, RIL_PERSOSUBSTATE_UNKNOWN,
2793 NULL, NULL, 0, RIL_PINSTATE_UNKNOWN, RIL_PINSTATE_UNKNOWN },
John Wang309ac292009-07-30 14:53:23 -07002794 // SIM_NOT_READY = 1
Wink Savillef6aa7c12009-04-30 14:20:52 -07002795 { RIL_APPTYPE_SIM, RIL_APPSTATE_DETECTED, RIL_PERSOSUBSTATE_UNKNOWN,
2796 NULL, NULL, 0, RIL_PINSTATE_UNKNOWN, RIL_PINSTATE_UNKNOWN },
John Wang309ac292009-07-30 14:53:23 -07002797 // SIM_READY = 2
Wink Savillef6aa7c12009-04-30 14:20:52 -07002798 { RIL_APPTYPE_SIM, RIL_APPSTATE_READY, RIL_PERSOSUBSTATE_READY,
2799 NULL, NULL, 0, RIL_PINSTATE_UNKNOWN, RIL_PINSTATE_UNKNOWN },
John Wang309ac292009-07-30 14:53:23 -07002800 // SIM_PIN = 3
Wink Savillef6aa7c12009-04-30 14:20:52 -07002801 { RIL_APPTYPE_SIM, RIL_APPSTATE_PIN, RIL_PERSOSUBSTATE_UNKNOWN,
2802 NULL, NULL, 0, RIL_PINSTATE_ENABLED_NOT_VERIFIED, RIL_PINSTATE_UNKNOWN },
John Wang309ac292009-07-30 14:53:23 -07002803 // SIM_PUK = 4
Wink Savillef6aa7c12009-04-30 14:20:52 -07002804 { RIL_APPTYPE_SIM, RIL_APPSTATE_PUK, RIL_PERSOSUBSTATE_UNKNOWN,
2805 NULL, NULL, 0, RIL_PINSTATE_ENABLED_BLOCKED, RIL_PINSTATE_UNKNOWN },
John Wang309ac292009-07-30 14:53:23 -07002806 // SIM_NETWORK_PERSONALIZATION = 5
Wink Savillef6aa7c12009-04-30 14:20:52 -07002807 { RIL_APPTYPE_SIM, RIL_APPSTATE_SUBSCRIPTION_PERSO, RIL_PERSOSUBSTATE_SIM_NETWORK,
Jaime A Lopez-Sollanoe9645042012-08-29 07:27:27 -07002808 NULL, NULL, 0, RIL_PINSTATE_ENABLED_NOT_VERIFIED, RIL_PINSTATE_UNKNOWN },
2809 // RUIM_ABSENT = 6
2810 { RIL_APPTYPE_UNKNOWN, RIL_APPSTATE_UNKNOWN, RIL_PERSOSUBSTATE_UNKNOWN,
2811 NULL, NULL, 0, RIL_PINSTATE_UNKNOWN, RIL_PINSTATE_UNKNOWN },
2812 // RUIM_NOT_READY = 7
2813 { RIL_APPTYPE_RUIM, RIL_APPSTATE_DETECTED, RIL_PERSOSUBSTATE_UNKNOWN,
2814 NULL, NULL, 0, RIL_PINSTATE_UNKNOWN, RIL_PINSTATE_UNKNOWN },
2815 // RUIM_READY = 8
2816 { RIL_APPTYPE_RUIM, RIL_APPSTATE_READY, RIL_PERSOSUBSTATE_READY,
2817 NULL, NULL, 0, RIL_PINSTATE_UNKNOWN, RIL_PINSTATE_UNKNOWN },
2818 // RUIM_PIN = 9
2819 { RIL_APPTYPE_RUIM, RIL_APPSTATE_PIN, RIL_PERSOSUBSTATE_UNKNOWN,
2820 NULL, NULL, 0, RIL_PINSTATE_ENABLED_NOT_VERIFIED, RIL_PINSTATE_UNKNOWN },
2821 // RUIM_PUK = 10
2822 { RIL_APPTYPE_RUIM, RIL_APPSTATE_PUK, RIL_PERSOSUBSTATE_UNKNOWN,
2823 NULL, NULL, 0, RIL_PINSTATE_ENABLED_BLOCKED, RIL_PINSTATE_UNKNOWN },
2824 // RUIM_NETWORK_PERSONALIZATION = 11
2825 { RIL_APPTYPE_RUIM, RIL_APPSTATE_SUBSCRIPTION_PERSO, RIL_PERSOSUBSTATE_SIM_NETWORK,
2826 NULL, NULL, 0, RIL_PINSTATE_ENABLED_NOT_VERIFIED, RIL_PINSTATE_UNKNOWN }
Wink Savillef6aa7c12009-04-30 14:20:52 -07002827 };
2828 RIL_CardState card_state;
2829 int num_apps;
2830
2831 int sim_status = getSIMStatus();
John Wang309ac292009-07-30 14:53:23 -07002832 if (sim_status == SIM_ABSENT) {
Wink Savillef6aa7c12009-04-30 14:20:52 -07002833 card_state = RIL_CARDSTATE_ABSENT;
2834 num_apps = 0;
2835 } else {
2836 card_state = RIL_CARDSTATE_PRESENT;
Jaime A Lopez-Sollanoe9645042012-08-29 07:27:27 -07002837 num_apps = 2;
Wink Savillef6aa7c12009-04-30 14:20:52 -07002838 }
2839
2840 // Allocate and initialize base card status.
Wink Saville2c1fb3a2011-03-19 13:42:45 -07002841 RIL_CardStatus_v6 *p_card_status = malloc(sizeof(RIL_CardStatus_v6));
Wink Savillef6aa7c12009-04-30 14:20:52 -07002842 p_card_status->card_state = card_state;
2843 p_card_status->universal_pin_state = RIL_PINSTATE_UNKNOWN;
2844 p_card_status->gsm_umts_subscription_app_index = RIL_CARD_MAX_APPS;
2845 p_card_status->cdma_subscription_app_index = RIL_CARD_MAX_APPS;
Wink Saville2c1fb3a2011-03-19 13:42:45 -07002846 p_card_status->ims_subscription_app_index = RIL_CARD_MAX_APPS;
Wink Savillef6aa7c12009-04-30 14:20:52 -07002847 p_card_status->num_applications = num_apps;
2848
2849 // Initialize application status
2850 int i;
2851 for (i = 0; i < RIL_CARD_MAX_APPS; i++) {
John Wang309ac292009-07-30 14:53:23 -07002852 p_card_status->applications[i] = app_status_array[SIM_ABSENT];
Wink Savillef6aa7c12009-04-30 14:20:52 -07002853 }
2854
2855 // Pickup the appropriate application status
2856 // that reflects sim_status for gsm.
2857 if (num_apps != 0) {
2858 // Only support one app, gsm
Jaime A Lopez-Sollanoe9645042012-08-29 07:27:27 -07002859 p_card_status->num_applications = 2;
Wink Savillef6aa7c12009-04-30 14:20:52 -07002860 p_card_status->gsm_umts_subscription_app_index = 0;
Jaime A Lopez-Sollanoe9645042012-08-29 07:27:27 -07002861 p_card_status->cdma_subscription_app_index = 1;
Wink Savillef6aa7c12009-04-30 14:20:52 -07002862
2863 // Get the correct app status
2864 p_card_status->applications[0] = app_status_array[sim_status];
Jaime A Lopez-Sollanoe9645042012-08-29 07:27:27 -07002865 p_card_status->applications[1] = app_status_array[sim_status + RUIM_ABSENT];
Wink Savillef6aa7c12009-04-30 14:20:52 -07002866 }
2867
2868 *pp_card_status = p_card_status;
2869 return RIL_E_SUCCESS;
2870}
2871
2872/**
2873 * Free the card status returned by getCardStatus
2874 */
Wink Saville2c1fb3a2011-03-19 13:42:45 -07002875static void freeCardStatus(RIL_CardStatus_v6 *p_card_status) {
Wink Savillef6aa7c12009-04-30 14:20:52 -07002876 free(p_card_status);
2877}
2878
2879/**
The Android Open Source Project00f06fc2009-03-03 19:32:15 -08002880 * SIM ready means any commands that access the SIM will work, including:
2881 * AT+CPIN, AT+CSMS, AT+CNMI, AT+CRSM
2882 * (all SMS-related commands)
2883 */
2884
Mark Salyzynba58c202014-03-12 15:20:22 -07002885static void pollSIMState (void *param __unused)
The Android Open Source Project00f06fc2009-03-03 19:32:15 -08002886{
2887 ATResponse *p_response;
2888 int ret;
2889
Naveen Kalla2baf7232016-10-11 13:49:20 -07002890 if (sState != RADIO_STATE_UNAVAILABLE) {
The Android Open Source Project00f06fc2009-03-03 19:32:15 -08002891 // no longer valid to poll
2892 return;
2893 }
2894
2895 switch(getSIMStatus()) {
John Wang309ac292009-07-30 14:53:23 -07002896 case SIM_ABSENT:
2897 case SIM_PIN:
2898 case SIM_PUK:
2899 case SIM_NETWORK_PERSONALIZATION:
The Android Open Source Project00f06fc2009-03-03 19:32:15 -08002900 default:
Wink Saville4dcab4f2012-11-19 16:05:13 -08002901 RLOGI("SIM ABSENT or LOCKED");
Jaime A Lopez-Sollanoe9645042012-08-29 07:27:27 -07002902 RIL_onUnsolicitedResponse(RIL_UNSOL_RESPONSE_SIM_STATUS_CHANGED, NULL, 0);
The Android Open Source Project00f06fc2009-03-03 19:32:15 -08002903 return;
2904
John Wang309ac292009-07-30 14:53:23 -07002905 case SIM_NOT_READY:
The Android Open Source Project00f06fc2009-03-03 19:32:15 -08002906 RIL_requestTimedCallback (pollSIMState, NULL, &TIMEVAL_SIMPOLL);
2907 return;
2908
John Wang309ac292009-07-30 14:53:23 -07002909 case SIM_READY:
Wink Saville4dcab4f2012-11-19 16:05:13 -08002910 RLOGI("SIM_READY");
Jaime A Lopez-Sollanoe9645042012-08-29 07:27:27 -07002911 onSIMReady();
2912 RIL_onUnsolicitedResponse(RIL_UNSOL_RESPONSE_SIM_STATUS_CHANGED, NULL, 0);
The Android Open Source Project00f06fc2009-03-03 19:32:15 -08002913 return;
2914 }
2915}
2916
2917/** returns 1 if on, 0 if off, and -1 on error */
2918static int isRadioOn()
2919{
2920 ATResponse *p_response = NULL;
2921 int err;
2922 char *line;
2923 char ret;
2924
2925 err = at_send_command_singleline("AT+CFUN?", "+CFUN:", &p_response);
2926
2927 if (err < 0 || p_response->success == 0) {
2928 // assume radio is off
2929 goto error;
2930 }
2931
2932 line = p_response->p_intermediates->line;
2933
2934 err = at_tok_start(&line);
2935 if (err < 0) goto error;
2936
2937 err = at_tok_nextbool(&line, &ret);
2938 if (err < 0) goto error;
2939
2940 at_response_free(p_response);
2941
2942 return (int)ret;
2943
2944error:
2945
2946 at_response_free(p_response);
2947 return -1;
2948}
2949
2950/**
Jaime A Lopez-Sollanoe9645042012-08-29 07:27:27 -07002951 * Parse the response generated by a +CTEC AT command
2952 * The values read from the response are stored in current and preferred.
2953 * Both current and preferred may be null. The corresponding value is ignored in that case.
2954 *
2955 * @return: -1 if some error occurs (or if the modem doesn't understand the +CTEC command)
2956 * 1 if the response includes the current technology only
2957 * 0 if the response includes both current technology and preferred mode
2958 */
2959int parse_technology_response( const char *response, int *current, int32_t *preferred )
2960{
2961 int err;
2962 char *line, *p;
2963 int ct;
2964 int32_t pt = 0;
2965 char *str_pt;
2966
2967 line = p = strdup(response);
Wink Saville4dcab4f2012-11-19 16:05:13 -08002968 RLOGD("Response: %s", line);
Jaime A Lopez-Sollanoe9645042012-08-29 07:27:27 -07002969 err = at_tok_start(&p);
2970 if (err || !at_tok_hasmore(&p)) {
Wink Saville4dcab4f2012-11-19 16:05:13 -08002971 RLOGD("err: %d. p: %s", err, p);
Jaime A Lopez-Sollanoe9645042012-08-29 07:27:27 -07002972 free(line);
2973 return -1;
2974 }
2975
2976 err = at_tok_nextint(&p, &ct);
2977 if (err) {
2978 free(line);
2979 return -1;
2980 }
2981 if (current) *current = ct;
2982
Wink Saville4dcab4f2012-11-19 16:05:13 -08002983 RLOGD("line remaining after int: %s", p);
Jaime A Lopez-Sollanoe9645042012-08-29 07:27:27 -07002984
2985 err = at_tok_nexthexint(&p, &pt);
2986 if (err) {
2987 free(line);
2988 return 1;
2989 }
2990 if (preferred) {
2991 *preferred = pt;
2992 }
2993 free(line);
2994
2995 return 0;
2996}
2997
Mark Salyzynba58c202014-03-12 15:20:22 -07002998int query_supported_techs( ModemInfo *mdm __unused, int *supported )
Jaime A Lopez-Sollanoe9645042012-08-29 07:27:27 -07002999{
3000 ATResponse *p_response;
3001 int err, val, techs = 0;
3002 char *tok;
3003 char *line;
3004
Wink Saville4dcab4f2012-11-19 16:05:13 -08003005 RLOGD("query_supported_techs");
Jaime A Lopez-Sollanoe9645042012-08-29 07:27:27 -07003006 err = at_send_command_singleline("AT+CTEC=?", "+CTEC:", &p_response);
3007 if (err || !p_response->success)
3008 goto error;
3009 line = p_response->p_intermediates->line;
3010 err = at_tok_start(&line);
3011 if (err || !at_tok_hasmore(&line))
3012 goto error;
3013 while (!at_tok_nextint(&line, &val)) {
3014 techs |= ( 1 << val );
3015 }
3016 if (supported) *supported = techs;
3017 return 0;
3018error:
3019 at_response_free(p_response);
3020 return -1;
3021}
3022
3023/**
3024 * query_ctec. Send the +CTEC AT command to the modem to query the current
3025 * and preferred modes. It leaves values in the addresses pointed to by
3026 * current and preferred. If any of those pointers are NULL, the corresponding value
3027 * is ignored, but the return value will still reflect if retreiving and parsing of the
3028 * values suceeded.
3029 *
3030 * @mdm Currently unused
3031 * @current A pointer to store the current mode returned by the modem. May be null.
3032 * @preferred A pointer to store the preferred mode returned by the modem. May be null.
3033 * @return -1 on error (or failure to parse)
3034 * 1 if only the current mode was returned by modem (or failed to parse preferred)
3035 * 0 if both current and preferred were returned correctly
3036 */
Mark Salyzynba58c202014-03-12 15:20:22 -07003037int query_ctec(ModemInfo *mdm __unused, int *current, int32_t *preferred)
Jaime A Lopez-Sollanoe9645042012-08-29 07:27:27 -07003038{
3039 ATResponse *response = NULL;
3040 int err;
3041 int res;
3042
Colin Cross5cba4882014-02-05 18:55:42 -08003043 RLOGD("query_ctec. current: %p, preferred: %p", current, preferred);
Jaime A Lopez-Sollanoe9645042012-08-29 07:27:27 -07003044 err = at_send_command_singleline("AT+CTEC?", "+CTEC:", &response);
3045 if (!err && response->success) {
3046 res = parse_technology_response(response->p_intermediates->line, current, preferred);
3047 at_response_free(response);
3048 return res;
3049 }
Colin Cross5cba4882014-02-05 18:55:42 -08003050 RLOGE("Error executing command: %d. response: %p. status: %d", err, response, response? response->success : -1);
Jaime A Lopez-Sollanoe9645042012-08-29 07:27:27 -07003051 at_response_free(response);
3052 return -1;
3053}
3054
3055int is_multimode_modem(ModemInfo *mdm)
3056{
3057 ATResponse *response;
3058 int err;
3059 char *line;
3060 int tech;
3061 int32_t preferred;
3062
3063 if (query_ctec(mdm, &tech, &preferred) == 0) {
3064 mdm->currentTech = tech;
3065 mdm->preferredNetworkMode = preferred;
3066 if (query_supported_techs(mdm, &mdm->supportedTechs)) {
3067 return 0;
3068 }
3069 return 1;
3070 }
3071 return 0;
3072}
3073
3074/**
3075 * Find out if our modem is GSM, CDMA or both (Multimode)
3076 */
3077static void probeForModemMode(ModemInfo *info)
3078{
3079 ATResponse *response;
3080 int err;
3081 assert (info);
3082 // Currently, our only known multimode modem is qemu's android modem,
3083 // which implements the AT+CTEC command to query and set mode.
3084 // Try that first
3085
3086 if (is_multimode_modem(info)) {
Wink Saville4dcab4f2012-11-19 16:05:13 -08003087 RLOGI("Found Multimode Modem. Supported techs mask: %8.8x. Current tech: %d",
Jaime A Lopez-Sollanoe9645042012-08-29 07:27:27 -07003088 info->supportedTechs, info->currentTech);
3089 return;
3090 }
3091
3092 /* Being here means that our modem is not multimode */
3093 info->isMultimode = 0;
3094
3095 /* CDMA Modems implement the AT+WNAM command */
3096 err = at_send_command_singleline("AT+WNAM","+WNAM:", &response);
3097 if (!err && response->success) {
3098 at_response_free(response);
3099 // TODO: find out if we really support EvDo
3100 info->supportedTechs = MDM_CDMA | MDM_EVDO;
3101 info->currentTech = MDM_CDMA;
Wink Saville4dcab4f2012-11-19 16:05:13 -08003102 RLOGI("Found CDMA Modem");
Jaime A Lopez-Sollanoe9645042012-08-29 07:27:27 -07003103 return;
3104 }
3105 if (!err) at_response_free(response);
3106 // TODO: find out if modem really supports WCDMA/LTE
3107 info->supportedTechs = MDM_GSM | MDM_WCDMA | MDM_LTE;
3108 info->currentTech = MDM_GSM;
Wink Saville4dcab4f2012-11-19 16:05:13 -08003109 RLOGI("Found GSM Modem");
Jaime A Lopez-Sollanoe9645042012-08-29 07:27:27 -07003110}
3111
3112/**
The Android Open Source Project00f06fc2009-03-03 19:32:15 -08003113 * Initialize everything that can be configured while we're still in
3114 * AT+CFUN=0
3115 */
Mark Salyzynba58c202014-03-12 15:20:22 -07003116static void initializeCallback(void *param __unused)
The Android Open Source Project00f06fc2009-03-03 19:32:15 -08003117{
3118 ATResponse *p_response = NULL;
3119 int err;
3120
3121 setRadioState (RADIO_STATE_OFF);
3122
3123 at_handshake();
3124
Jaime A Lopez-Sollanoe9645042012-08-29 07:27:27 -07003125 probeForModemMode(sMdmInfo);
The Android Open Source Project00f06fc2009-03-03 19:32:15 -08003126 /* note: we don't check errors here. Everything important will
3127 be handled in onATTimeout and onATReaderClosed */
3128
3129 /* atchannel is tolerant of echo but it must */
3130 /* have verbose result codes */
3131 at_send_command("ATE0Q0V1", NULL);
3132
3133 /* No auto-answer */
3134 at_send_command("ATS0=0", NULL);
3135
3136 /* Extended errors */
3137 at_send_command("AT+CMEE=1", NULL);
3138
3139 /* Network registration events */
3140 err = at_send_command("AT+CREG=2", &p_response);
3141
3142 /* some handsets -- in tethered mode -- don't support CREG=2 */
3143 if (err < 0 || p_response->success == 0) {
3144 at_send_command("AT+CREG=1", NULL);
3145 }
3146
3147 at_response_free(p_response);
3148
3149 /* GPRS registration events */
3150 at_send_command("AT+CGREG=1", NULL);
3151
3152 /* Call Waiting notifications */
3153 at_send_command("AT+CCWA=1", NULL);
3154
3155 /* Alternating voice/data off */
3156 at_send_command("AT+CMOD=0", NULL);
3157
3158 /* Not muted */
3159 at_send_command("AT+CMUT=0", NULL);
3160
3161 /* +CSSU unsolicited supp service notifications */
3162 at_send_command("AT+CSSN=0,1", NULL);
3163
3164 /* no connected line identification */
3165 at_send_command("AT+COLP=0", NULL);
3166
3167 /* HEX character set */
3168 at_send_command("AT+CSCS=\"HEX\"", NULL);
3169
3170 /* USSD unsolicited */
3171 at_send_command("AT+CUSD=1", NULL);
3172
3173 /* Enable +CGEV GPRS event notifications, but don't buffer */
3174 at_send_command("AT+CGEREP=1,0", NULL);
3175
3176 /* SMS PDU mode */
3177 at_send_command("AT+CMGF=0", NULL);
3178
3179#ifdef USE_TI_COMMANDS
3180
3181 at_send_command("AT%CPI=3", NULL);
3182
3183 /* TI specific -- notifications when SMS is ready (currently ignored) */
3184 at_send_command("AT%CSTAT=1", NULL);
3185
3186#endif /* USE_TI_COMMANDS */
3187
3188
3189 /* assume radio is off on error */
3190 if (isRadioOn() > 0) {
Jaime A Lopez-Sollanoe9645042012-08-29 07:27:27 -07003191 setRadioState (RADIO_STATE_ON);
The Android Open Source Project00f06fc2009-03-03 19:32:15 -08003192 }
3193}
3194
3195static void waitForClose()
3196{
3197 pthread_mutex_lock(&s_state_mutex);
3198
3199 while (s_closed == 0) {
3200 pthread_cond_wait(&s_state_cond, &s_state_mutex);
3201 }
3202
3203 pthread_mutex_unlock(&s_state_mutex);
3204}
3205
Sukanya Rajkhowaa18b9d12013-09-10 12:30:13 -07003206static void sendUnsolImsNetworkStateChanged()
3207{
3208#if 0 // to be used when unsol is changed to return data.
3209 int reply[2];
3210 reply[0] = s_ims_registered;
3211 reply[1] = s_ims_services;
3212 reply[1] = s_ims_format;
3213#endif
3214 RIL_onUnsolicitedResponse(RIL_UNSOL_RESPONSE_IMS_NETWORK_STATE_CHANGED,
3215 NULL, 0);
3216}
3217
The Android Open Source Project00f06fc2009-03-03 19:32:15 -08003218/**
3219 * Called by atchannel when an unsolicited line appears
3220 * This is called on atchannel's reader thread. AT commands may
3221 * not be issued here
3222 */
3223static void onUnsolicited (const char *s, const char *sms_pdu)
3224{
Jaime A Lopez-Sollanoe9645042012-08-29 07:27:27 -07003225 char *line = NULL, *p;
The Android Open Source Project00f06fc2009-03-03 19:32:15 -08003226 int err;
3227
3228 /* Ignore unsolicited responses until we're initialized.
3229 * This is OK because the RIL library will poll for initial state
3230 */
3231 if (sState == RADIO_STATE_UNAVAILABLE) {
3232 return;
3233 }
3234
3235 if (strStartsWith(s, "%CTZV:")) {
3236 /* TI specific -- NITZ time */
3237 char *response;
3238
Jaime A Lopez-Sollanoe9645042012-08-29 07:27:27 -07003239 line = p = strdup(s);
3240 at_tok_start(&p);
The Android Open Source Project00f06fc2009-03-03 19:32:15 -08003241
Jaime A Lopez-Sollanoe9645042012-08-29 07:27:27 -07003242 err = at_tok_nextstr(&p, &response);
The Android Open Source Project00f06fc2009-03-03 19:32:15 -08003243
3244 if (err != 0) {
Wink Saville4dcab4f2012-11-19 16:05:13 -08003245 RLOGE("invalid NITZ line %s\n", s);
The Android Open Source Project00f06fc2009-03-03 19:32:15 -08003246 } else {
3247 RIL_onUnsolicitedResponse (
3248 RIL_UNSOL_NITZ_TIME_RECEIVED,
3249 response, strlen(response));
3250 }
Ivan Krasin7c0165e2015-12-03 15:50:10 -08003251 free(line);
The Android Open Source Project00f06fc2009-03-03 19:32:15 -08003252 } else if (strStartsWith(s,"+CRING:")
3253 || strStartsWith(s,"RING")
3254 || strStartsWith(s,"NO CARRIER")
3255 || strStartsWith(s,"+CCWA")
3256 ) {
3257 RIL_onUnsolicitedResponse (
3258 RIL_UNSOL_RESPONSE_CALL_STATE_CHANGED,
3259 NULL, 0);
3260#ifdef WORKAROUND_FAKE_CGEV
Wink Savillef4c4d362009-04-02 01:37:03 -07003261 RIL_requestTimedCallback (onDataCallListChanged, NULL, NULL); //TODO use new function
The Android Open Source Project00f06fc2009-03-03 19:32:15 -08003262#endif /* WORKAROUND_FAKE_CGEV */
3263 } else if (strStartsWith(s,"+CREG:")
3264 || strStartsWith(s,"+CGREG:")
3265 ) {
3266 RIL_onUnsolicitedResponse (
Wink Saville2c1fb3a2011-03-19 13:42:45 -07003267 RIL_UNSOL_RESPONSE_VOICE_NETWORK_STATE_CHANGED,
The Android Open Source Project00f06fc2009-03-03 19:32:15 -08003268 NULL, 0);
3269#ifdef WORKAROUND_FAKE_CGEV
Wink Saville7f856802009-06-09 10:23:37 -07003270 RIL_requestTimedCallback (onDataCallListChanged, NULL, NULL);
The Android Open Source Project00f06fc2009-03-03 19:32:15 -08003271#endif /* WORKAROUND_FAKE_CGEV */
3272 } else if (strStartsWith(s, "+CMT:")) {
3273 RIL_onUnsolicitedResponse (
3274 RIL_UNSOL_RESPONSE_NEW_SMS,
3275 sms_pdu, strlen(sms_pdu));
3276 } else if (strStartsWith(s, "+CDS:")) {
3277 RIL_onUnsolicitedResponse (
3278 RIL_UNSOL_RESPONSE_NEW_SMS_STATUS_REPORT,
3279 sms_pdu, strlen(sms_pdu));
3280 } else if (strStartsWith(s, "+CGEV:")) {
3281 /* Really, we can ignore NW CLASS and ME CLASS events here,
3282 * but right now we don't since extranous
Wink Savillef4c4d362009-04-02 01:37:03 -07003283 * RIL_UNSOL_DATA_CALL_LIST_CHANGED calls are tolerated
The Android Open Source Project00f06fc2009-03-03 19:32:15 -08003284 */
3285 /* can't issue AT commands here -- call on main thread */
Wink Savillef4c4d362009-04-02 01:37:03 -07003286 RIL_requestTimedCallback (onDataCallListChanged, NULL, NULL);
The Android Open Source Project00f06fc2009-03-03 19:32:15 -08003287#ifdef WORKAROUND_FAKE_CGEV
3288 } else if (strStartsWith(s, "+CME ERROR: 150")) {
Wink Savillef4c4d362009-04-02 01:37:03 -07003289 RIL_requestTimedCallback (onDataCallListChanged, NULL, NULL);
The Android Open Source Project00f06fc2009-03-03 19:32:15 -08003290#endif /* WORKAROUND_FAKE_CGEV */
Jaime A Lopez-Sollanoe9645042012-08-29 07:27:27 -07003291 } else if (strStartsWith(s, "+CTEC: ")) {
3292 int tech, mask;
3293 switch (parse_technology_response(s, &tech, NULL))
3294 {
3295 case -1: // no argument could be parsed.
Wink Saville4dcab4f2012-11-19 16:05:13 -08003296 RLOGE("invalid CTEC line %s\n", s);
Jaime A Lopez-Sollanoe9645042012-08-29 07:27:27 -07003297 break;
3298 case 1: // current mode correctly parsed
3299 case 0: // preferred mode correctly parsed
3300 mask = 1 << tech;
3301 if (mask != MDM_GSM && mask != MDM_CDMA &&
3302 mask != MDM_WCDMA && mask != MDM_LTE) {
Wink Saville4dcab4f2012-11-19 16:05:13 -08003303 RLOGE("Unknown technology %d\n", tech);
Jaime A Lopez-Sollanoe9645042012-08-29 07:27:27 -07003304 } else {
3305 setRadioTechnology(sMdmInfo, tech);
3306 }
3307 break;
3308 }
3309 } else if (strStartsWith(s, "+CCSS: ")) {
3310 int source = 0;
3311 line = p = strdup(s);
3312 if (!line) {
Wink Saville4dcab4f2012-11-19 16:05:13 -08003313 RLOGE("+CCSS: Unable to allocate memory");
Jaime A Lopez-Sollanoe9645042012-08-29 07:27:27 -07003314 return;
3315 }
3316 if (at_tok_start(&p) < 0) {
3317 free(line);
3318 return;
3319 }
3320 if (at_tok_nextint(&p, &source) < 0) {
Wink Saville4dcab4f2012-11-19 16:05:13 -08003321 RLOGE("invalid +CCSS response: %s", line);
Jaime A Lopez-Sollanoe9645042012-08-29 07:27:27 -07003322 free(line);
3323 return;
3324 }
3325 SSOURCE(sMdmInfo) = source;
3326 RIL_onUnsolicitedResponse(RIL_UNSOL_CDMA_SUBSCRIPTION_SOURCE_CHANGED,
3327 &source, sizeof(source));
3328 } else if (strStartsWith(s, "+WSOS: ")) {
3329 char state = 0;
3330 int unsol;
3331 line = p = strdup(s);
3332 if (!line) {
Wink Saville4dcab4f2012-11-19 16:05:13 -08003333 RLOGE("+WSOS: Unable to allocate memory");
Jaime A Lopez-Sollanoe9645042012-08-29 07:27:27 -07003334 return;
3335 }
3336 if (at_tok_start(&p) < 0) {
3337 free(line);
3338 return;
3339 }
3340 if (at_tok_nextbool(&p, &state) < 0) {
Wink Saville4dcab4f2012-11-19 16:05:13 -08003341 RLOGE("invalid +WSOS response: %s", line);
Jaime A Lopez-Sollanoe9645042012-08-29 07:27:27 -07003342 free(line);
3343 return;
3344 }
3345 free(line);
3346
3347 unsol = state ?
3348 RIL_UNSOL_ENTER_EMERGENCY_CALLBACK_MODE : RIL_UNSOL_EXIT_EMERGENCY_CALLBACK_MODE;
3349
3350 RIL_onUnsolicitedResponse(unsol, NULL, 0);
3351
3352 } else if (strStartsWith(s, "+WPRL: ")) {
3353 int version = -1;
3354 line = p = strdup(s);
3355 if (!line) {
Wink Saville4dcab4f2012-11-19 16:05:13 -08003356 RLOGE("+WPRL: Unable to allocate memory");
Jaime A Lopez-Sollanoe9645042012-08-29 07:27:27 -07003357 return;
3358 }
3359 if (at_tok_start(&p) < 0) {
Wink Saville4dcab4f2012-11-19 16:05:13 -08003360 RLOGE("invalid +WPRL response: %s", s);
Jaime A Lopez-Sollanoe9645042012-08-29 07:27:27 -07003361 free(line);
3362 return;
3363 }
3364 if (at_tok_nextint(&p, &version) < 0) {
Wink Saville4dcab4f2012-11-19 16:05:13 -08003365 RLOGE("invalid +WPRL response: %s", s);
Jaime A Lopez-Sollanoe9645042012-08-29 07:27:27 -07003366 free(line);
3367 return;
3368 }
3369 free(line);
3370 RIL_onUnsolicitedResponse(RIL_UNSOL_CDMA_PRL_CHANGED, &version, sizeof(version));
3371 } else if (strStartsWith(s, "+CFUN: 0")) {
3372 setRadioState(RADIO_STATE_OFF);
The Android Open Source Project00f06fc2009-03-03 19:32:15 -08003373 }
3374}
3375
3376/* Called on command or reader thread */
3377static void onATReaderClosed()
3378{
Wink Saville4dcab4f2012-11-19 16:05:13 -08003379 RLOGI("AT channel closed\n");
The Android Open Source Project00f06fc2009-03-03 19:32:15 -08003380 at_close();
3381 s_closed = 1;
3382
3383 setRadioState (RADIO_STATE_UNAVAILABLE);
3384}
3385
3386/* Called on command thread */
3387static void onATTimeout()
3388{
Wink Saville4dcab4f2012-11-19 16:05:13 -08003389 RLOGI("AT channel timeout; closing\n");
The Android Open Source Project00f06fc2009-03-03 19:32:15 -08003390 at_close();
3391
3392 s_closed = 1;
3393
3394 /* FIXME cause a radio reset here */
3395
3396 setRadioState (RADIO_STATE_UNAVAILABLE);
3397}
3398
Etan Cohend3652192014-06-20 08:28:44 -07003399/* Called to pass hardware configuration information to telephony
3400 * framework.
3401 */
3402static void setHardwareConfiguration(int num, RIL_HardwareConfig *cfg)
3403{
3404 RIL_onUnsolicitedResponse(RIL_UNSOL_HARDWARE_CONFIG_CHANGED, cfg, num*sizeof(*cfg));
3405}
3406
Sanket Padawef0c8ca72016-06-30 15:01:08 -07003407static void usage(char *s __unused)
The Android Open Source Project00f06fc2009-03-03 19:32:15 -08003408{
3409#ifdef RIL_SHLIB
3410 fprintf(stderr, "reference-ril requires: -p <tcp port> or -d /dev/tty_device\n");
3411#else
3412 fprintf(stderr, "usage: %s [-p <tcp port>] [-d /dev/tty_device]\n", s);
3413 exit(-1);
3414#endif
3415}
3416
3417static void *
Mark Salyzynba58c202014-03-12 15:20:22 -07003418mainLoop(void *param __unused)
The Android Open Source Project00f06fc2009-03-03 19:32:15 -08003419{
3420 int fd;
3421 int ret;
3422
3423 AT_DUMP("== ", "entering mainLoop()", -1 );
3424 at_set_on_reader_closed(onATReaderClosed);
3425 at_set_on_timeout(onATTimeout);
3426
3427 for (;;) {
3428 fd = -1;
3429 while (fd < 0) {
David 'Digit' Turner834eca82016-06-22 12:10:01 +02003430 if (isInEmulator()) {
3431 fd = qemu_pipe_open("pipe:qemud:gsm");
3432 } else if (s_port > 0) {
Elliott Hughes7e3bbd42016-10-11 13:50:06 -07003433 fd = socket_network_client("localhost", s_port, SOCK_STREAM);
The Android Open Source Project00f06fc2009-03-03 19:32:15 -08003434 } else if (s_device_socket) {
David 'Digit' Turner834eca82016-06-22 12:10:01 +02003435 fd = socket_local_client(s_device_path,
3436 ANDROID_SOCKET_NAMESPACE_FILESYSTEM,
3437 SOCK_STREAM);
The Android Open Source Project00f06fc2009-03-03 19:32:15 -08003438 } else if (s_device_path != NULL) {
3439 fd = open (s_device_path, O_RDWR);
3440 if ( fd >= 0 && !memcmp( s_device_path, "/dev/ttyS", 9 ) ) {
3441 /* disable echo on serial ports */
3442 struct termios ios;
3443 tcgetattr( fd, &ios );
3444 ios.c_lflag = 0; /* disable ECHO, ICANON, etc... */
3445 tcsetattr( fd, TCSANOW, &ios );
3446 }
3447 }
3448
3449 if (fd < 0) {
3450 perror ("opening AT interface. retrying...");
3451 sleep(10);
3452 /* never returns */
3453 }
3454 }
3455
3456 s_closed = 0;
3457 ret = at_open(fd, onUnsolicited);
3458
3459 if (ret < 0) {
Wink Saville4dcab4f2012-11-19 16:05:13 -08003460 RLOGE ("AT error %d on at_open\n", ret);
The Android Open Source Project00f06fc2009-03-03 19:32:15 -08003461 return 0;
3462 }
3463
3464 RIL_requestTimedCallback(initializeCallback, NULL, &TIMEVAL_0);
3465
3466 // Give initializeCallback a chance to dispatched, since
3467 // we don't presently have a cancellation mechanism
3468 sleep(1);
3469
3470 waitForClose();
Wink Saville4dcab4f2012-11-19 16:05:13 -08003471 RLOGI("Re-opening after close");
The Android Open Source Project00f06fc2009-03-03 19:32:15 -08003472 }
3473}
3474
3475#ifdef RIL_SHLIB
3476
3477pthread_t s_tid_mainloop;
3478
3479const RIL_RadioFunctions *RIL_Init(const struct RIL_Env *env, int argc, char **argv)
3480{
3481 int ret;
3482 int fd = -1;
3483 int opt;
3484 pthread_attr_t attr;
3485
3486 s_rilenv = env;
3487
Sandeep Gutta11f27942014-07-10 05:00:25 +05303488 while ( -1 != (opt = getopt(argc, argv, "p:d:s:c:"))) {
The Android Open Source Project00f06fc2009-03-03 19:32:15 -08003489 switch (opt) {
3490 case 'p':
3491 s_port = atoi(optarg);
3492 if (s_port == 0) {
3493 usage(argv[0]);
3494 return NULL;
3495 }
Wink Saville4dcab4f2012-11-19 16:05:13 -08003496 RLOGI("Opening loopback port %d\n", s_port);
The Android Open Source Project00f06fc2009-03-03 19:32:15 -08003497 break;
3498
3499 case 'd':
3500 s_device_path = optarg;
Wink Saville4dcab4f2012-11-19 16:05:13 -08003501 RLOGI("Opening tty device %s\n", s_device_path);
The Android Open Source Project00f06fc2009-03-03 19:32:15 -08003502 break;
3503
3504 case 's':
3505 s_device_path = optarg;
3506 s_device_socket = 1;
Wink Saville4dcab4f2012-11-19 16:05:13 -08003507 RLOGI("Opening socket %s\n", s_device_path);
The Android Open Source Project00f06fc2009-03-03 19:32:15 -08003508 break;
3509
Sandeep Gutta11f27942014-07-10 05:00:25 +05303510 case 'c':
3511 RLOGI("Client id received %s\n", optarg);
3512 break;
3513
The Android Open Source Project00f06fc2009-03-03 19:32:15 -08003514 default:
3515 usage(argv[0]);
3516 return NULL;
3517 }
3518 }
3519
David 'Digit' Turner834eca82016-06-22 12:10:01 +02003520 if (s_port < 0 && s_device_path == NULL && !isInEmulator()) {
The Android Open Source Project00f06fc2009-03-03 19:32:15 -08003521 usage(argv[0]);
3522 return NULL;
3523 }
3524
Jaime A Lopez-Sollanoe9645042012-08-29 07:27:27 -07003525 sMdmInfo = calloc(1, sizeof(ModemInfo));
3526 if (!sMdmInfo) {
Wink Saville4dcab4f2012-11-19 16:05:13 -08003527 RLOGE("Unable to alloc memory for ModemInfo");
Jaime A Lopez-Sollanoe9645042012-08-29 07:27:27 -07003528 return NULL;
3529 }
The Android Open Source Project00f06fc2009-03-03 19:32:15 -08003530 pthread_attr_init (&attr);
3531 pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
3532 ret = pthread_create(&s_tid_mainloop, &attr, mainLoop, NULL);
3533
3534 return &s_callbacks;
3535}
3536#else /* RIL_SHLIB */
3537int main (int argc, char **argv)
3538{
3539 int ret;
3540 int fd = -1;
3541 int opt;
3542
3543 while ( -1 != (opt = getopt(argc, argv, "p:d:"))) {
3544 switch (opt) {
3545 case 'p':
3546 s_port = atoi(optarg);
3547 if (s_port == 0) {
3548 usage(argv[0]);
3549 }
Wink Saville4dcab4f2012-11-19 16:05:13 -08003550 RLOGI("Opening loopback port %d\n", s_port);
The Android Open Source Project00f06fc2009-03-03 19:32:15 -08003551 break;
3552
3553 case 'd':
3554 s_device_path = optarg;
Wink Saville4dcab4f2012-11-19 16:05:13 -08003555 RLOGI("Opening tty device %s\n", s_device_path);
The Android Open Source Project00f06fc2009-03-03 19:32:15 -08003556 break;
3557
3558 case 's':
3559 s_device_path = optarg;
3560 s_device_socket = 1;
Wink Saville4dcab4f2012-11-19 16:05:13 -08003561 RLOGI("Opening socket %s\n", s_device_path);
The Android Open Source Project00f06fc2009-03-03 19:32:15 -08003562 break;
3563
3564 default:
3565 usage(argv[0]);
3566 }
3567 }
3568
David 'Digit' Turner834eca82016-06-22 12:10:01 +02003569 if (s_port < 0 && s_device_path == NULL && !isInEmulator()) {
The Android Open Source Project00f06fc2009-03-03 19:32:15 -08003570 usage(argv[0]);
3571 }
3572
3573 RIL_register(&s_callbacks);
3574
3575 mainLoop(NULL);
3576
3577 return 0;
3578}
3579
3580#endif /* RIL_SHLIB */