blob: 37c87b2755f970a535fea9864549e288c8f3446d [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
The Android Open Source Project00f06fc2009-03-03 19:32:15 -080018#include <stdio.h>
19#include <assert.h>
20#include <string.h>
21#include <errno.h>
22#include <unistd.h>
23#include <sys/types.h>
24#include <sys/stat.h>
25#include <fcntl.h>
26#include <pthread.h>
27#include <alloca.h>
28#include "atchannel.h"
29#include "at_tok.h"
30#include "misc.h"
31#include <getopt.h>
32#include <sys/socket.h>
33#include <cutils/sockets.h>
34#include <termios.h>
David 'Digit' Turneraf1298d2011-02-04 13:36:47 +010035#include <sys/system_properties.h>
The Android Open Source Project00f06fc2009-03-03 19:32:15 -080036
Wink Saville9a9fbd22011-02-15 17:13:10 -080037#include "ril.h"
Vladimir Chtchetkine385a7392011-08-04 14:03:07 -070038#include "hardware/qemu_pipe.h"
Wink Saville9a9fbd22011-02-15 17:13:10 -080039
The Android Open Source Project00f06fc2009-03-03 19:32:15 -080040#define LOG_TAG "RIL"
41#include <utils/Log.h>
42
43#define MAX_AT_RESPONSE 0x1000
44
Wink Savillef4c4d362009-04-02 01:37:03 -070045/* pathname returned from RIL_REQUEST_SETUP_DATA_CALL / RIL_REQUEST_SETUP_DEFAULT_PDP */
Robert Greenwaltf838ede2010-07-15 18:54:53 -070046#define PPP_TTY_PATH "eth0"
The Android Open Source Project00f06fc2009-03-03 19:32:15 -080047
48#ifdef USE_TI_COMMANDS
49
50// Enable a workaround
51// 1) Make incoming call, do not answer
52// 2) Hangup remote end
53// Expected: call should disappear from CLCC line
54// Actual: Call shows as "ACTIVE" before disappearing
55#define WORKAROUND_ERRONEOUS_ANSWER 1
56
57// Some varients of the TI stack do not support the +CGEV unsolicited
58// response. However, they seem to send an unsolicited +CME ERROR: 150
59#define WORKAROUND_FAKE_CGEV 1
60#endif
61
John Wang309ac292009-07-30 14:53:23 -070062typedef enum {
63 SIM_ABSENT = 0,
64 SIM_NOT_READY = 1,
65 SIM_READY = 2, /* SIM_READY means the radio state is RADIO_STATE_SIM_READY */
66 SIM_PIN = 3,
67 SIM_PUK = 4,
68 SIM_NETWORK_PERSONALIZATION = 5
David 'Digit' Turneraf1298d2011-02-04 13:36:47 +010069} SIM_Status;
John Wang309ac292009-07-30 14:53:23 -070070
The Android Open Source Project00f06fc2009-03-03 19:32:15 -080071static void onRequest (int request, void *data, size_t datalen, RIL_Token t);
72static RIL_RadioState currentState();
73static int onSupports (int requestCode);
74static void onCancel (RIL_Token t);
75static const char *getVersion();
76static int isRadioOn();
John Wang309ac292009-07-30 14:53:23 -070077static SIM_Status getSIMStatus();
Wink Saville2c1fb3a2011-03-19 13:42:45 -070078static int getCardStatus(RIL_CardStatus_v6 **pp_card_status);
79static void freeCardStatus(RIL_CardStatus_v6 *p_card_status);
Wink Savillef4c4d362009-04-02 01:37:03 -070080static void onDataCallListChanged(void *param);
The Android Open Source Project00f06fc2009-03-03 19:32:15 -080081
82extern const char * requestToString(int request);
83
84/*** Static Variables ***/
85static const RIL_RadioFunctions s_callbacks = {
86 RIL_VERSION,
87 onRequest,
88 currentState,
89 onSupports,
90 onCancel,
91 getVersion
92};
93
94#ifdef RIL_SHLIB
95static const struct RIL_Env *s_rilenv;
96
97#define RIL_onRequestComplete(t, e, response, responselen) s_rilenv->OnRequestComplete(t,e, response, responselen)
98#define RIL_onUnsolicitedResponse(a,b,c) s_rilenv->OnUnsolicitedResponse(a,b,c)
99#define RIL_requestTimedCallback(a,b,c) s_rilenv->RequestTimedCallback(a,b,c)
100#endif
101
102static RIL_RadioState sState = RADIO_STATE_UNAVAILABLE;
103
104static pthread_mutex_t s_state_mutex = PTHREAD_MUTEX_INITIALIZER;
105static pthread_cond_t s_state_cond = PTHREAD_COND_INITIALIZER;
106
107static int s_port = -1;
108static const char * s_device_path = NULL;
109static int s_device_socket = 0;
110
111/* trigger change to this with s_state_cond */
112static int s_closed = 0;
113
114static int sFD; /* file desc of AT channel */
115static char sATBuffer[MAX_AT_RESPONSE+1];
116static char *sATBufferCur = NULL;
117
118static const struct timeval TIMEVAL_SIMPOLL = {1,0};
119static const struct timeval TIMEVAL_CALLSTATEPOLL = {0,500000};
120static const struct timeval TIMEVAL_0 = {0,0};
121
122#ifdef WORKAROUND_ERRONEOUS_ANSWER
123// Max number of times we'll try to repoll when we think
124// we have a AT+CLCC race condition
125#define REPOLL_CALLS_COUNT_MAX 4
126
127// Line index that was incoming or waiting at last poll, or -1 for none
128static int s_incomingOrWaitingLine = -1;
129// Number of times we've asked for a repoll of AT+CLCC
130static int s_repollCallsCount = 0;
131// Should we expect a call to be answered in the next CLCC?
132static int s_expectAnswer = 0;
133#endif /* WORKAROUND_ERRONEOUS_ANSWER */
134
135static void pollSIMState (void *param);
136static void setRadioState(RIL_RadioState newState);
137
138static int clccStateToRILState(int state, RIL_CallState *p_state)
139
140{
141 switch(state) {
142 case 0: *p_state = RIL_CALL_ACTIVE; return 0;
143 case 1: *p_state = RIL_CALL_HOLDING; return 0;
144 case 2: *p_state = RIL_CALL_DIALING; return 0;
145 case 3: *p_state = RIL_CALL_ALERTING; return 0;
146 case 4: *p_state = RIL_CALL_INCOMING; return 0;
147 case 5: *p_state = RIL_CALL_WAITING; return 0;
148 default: return -1;
149 }
150}
151
152/**
153 * Note: directly modified line and has *p_call point directly into
154 * modified line
155 */
Wink Saville3d54e742009-05-18 18:00:44 -0700156static int callFromCLCCLine(char *line, RIL_Call *p_call)
The Android Open Source Project00f06fc2009-03-03 19:32:15 -0800157{
158 //+CLCC: 1,0,2,0,0,\"+18005551212\",145
159 // index,isMT,state,mode,isMpty(,number,TOA)?
160
161 int err;
162 int state;
163 int mode;
164
165 err = at_tok_start(&line);
166 if (err < 0) goto error;
167
168 err = at_tok_nextint(&line, &(p_call->index));
169 if (err < 0) goto error;
170
171 err = at_tok_nextbool(&line, &(p_call->isMT));
172 if (err < 0) goto error;
173
174 err = at_tok_nextint(&line, &state);
175 if (err < 0) goto error;
176
177 err = clccStateToRILState(state, &(p_call->state));
178 if (err < 0) goto error;
179
180 err = at_tok_nextint(&line, &mode);
181 if (err < 0) goto error;
182
183 p_call->isVoice = (mode == 0);
184
185 err = at_tok_nextbool(&line, &(p_call->isMpty));
186 if (err < 0) goto error;
187
188 if (at_tok_hasmore(&line)) {
189 err = at_tok_nextstr(&line, &(p_call->number));
190
191 /* tolerate null here */
192 if (err < 0) return 0;
193
194 // Some lame implementations return strings
195 // like "NOT AVAILABLE" in the CLCC line
196 if (p_call->number != NULL
197 && 0 == strspn(p_call->number, "+0123456789")
198 ) {
199 p_call->number = NULL;
200 }
201
202 err = at_tok_nextint(&line, &p_call->toa);
203 if (err < 0) goto error;
204 }
205
Wink Saville74fa3882009-12-22 15:35:41 -0800206 p_call->uusInfo = NULL;
207
The Android Open Source Project00f06fc2009-03-03 19:32:15 -0800208 return 0;
209
210error:
Steve Block170fbda2012-01-08 13:48:26 +0000211 ALOGE("invalid CLCC line\n");
The Android Open Source Project00f06fc2009-03-03 19:32:15 -0800212 return -1;
213}
214
215
216/** do post-AT+CFUN=1 initialization */
217static void onRadioPowerOn()
218{
219#ifdef USE_TI_COMMANDS
220 /* Must be after CFUN=1 */
221 /* TI specific -- notifications for CPHS things such */
222 /* as CPHS message waiting indicator */
223
224 at_send_command("AT%CPHS=1", NULL);
225
226 /* TI specific -- enable NITZ unsol notifs */
227 at_send_command("AT%CTZV=1", NULL);
228#endif
229
230 pollSIMState(NULL);
231}
232
233/** do post- SIM ready initialization */
234static void onSIMReady()
235{
236 at_send_command_singleline("AT+CSMS=1", "+CSMS:", NULL);
237 /*
238 * Always send SMS messages directly to the TE
239 *
240 * mode = 1 // discard when link is reserved (link should never be
241 * reserved)
242 * mt = 2 // most messages routed to TE
243 * bm = 2 // new cell BM's routed to TE
244 * ds = 1 // Status reports routed to TE
245 * bfr = 1 // flush buffer
246 */
247 at_send_command("AT+CNMI=1,2,2,1,1", NULL);
248}
249
250static void requestRadioPower(void *data, size_t datalen, RIL_Token t)
251{
252 int onOff;
253
254 int err;
255 ATResponse *p_response = NULL;
256
257 assert (datalen >= sizeof(int *));
258 onOff = ((int *)data)[0];
259
260 if (onOff == 0 && sState != RADIO_STATE_OFF) {
261 err = at_send_command("AT+CFUN=0", &p_response);
262 if (err < 0 || p_response->success == 0) goto error;
263 setRadioState(RADIO_STATE_OFF);
264 } else if (onOff > 0 && sState == RADIO_STATE_OFF) {
265 err = at_send_command("AT+CFUN=1", &p_response);
266 if (err < 0|| p_response->success == 0) {
267 // Some stacks return an error when there is no SIM,
268 // but they really turn the RF portion on
269 // So, if we get an error, let's check to see if it
270 // turned on anyway
271
272 if (isRadioOn() != 1) {
273 goto error;
274 }
275 }
276 setRadioState(RADIO_STATE_SIM_NOT_READY);
277 }
278
279 at_response_free(p_response);
280 RIL_onRequestComplete(t, RIL_E_SUCCESS, NULL, 0);
281 return;
282error:
283 at_response_free(p_response);
284 RIL_onRequestComplete(t, RIL_E_GENERIC_FAILURE, NULL, 0);
285}
286
Wink Savillef4c4d362009-04-02 01:37:03 -0700287static void requestOrSendDataCallList(RIL_Token *t);
The Android Open Source Project00f06fc2009-03-03 19:32:15 -0800288
Wink Savillef4c4d362009-04-02 01:37:03 -0700289static void onDataCallListChanged(void *param)
The Android Open Source Project00f06fc2009-03-03 19:32:15 -0800290{
Wink Savillef4c4d362009-04-02 01:37:03 -0700291 requestOrSendDataCallList(NULL);
The Android Open Source Project00f06fc2009-03-03 19:32:15 -0800292}
293
Wink Savillef4c4d362009-04-02 01:37:03 -0700294static void requestDataCallList(void *data, size_t datalen, RIL_Token t)
The Android Open Source Project00f06fc2009-03-03 19:32:15 -0800295{
Wink Savillef4c4d362009-04-02 01:37:03 -0700296 requestOrSendDataCallList(&t);
The Android Open Source Project00f06fc2009-03-03 19:32:15 -0800297}
298
Wink Savillef4c4d362009-04-02 01:37:03 -0700299static void requestOrSendDataCallList(RIL_Token *t)
The Android Open Source Project00f06fc2009-03-03 19:32:15 -0800300{
301 ATResponse *p_response;
302 ATLine *p_cur;
303 int err;
304 int n = 0;
305 char *out;
306
307 err = at_send_command_multiline ("AT+CGACT?", "+CGACT:", &p_response);
308 if (err != 0 || p_response->success == 0) {
309 if (t != NULL)
310 RIL_onRequestComplete(*t, RIL_E_GENERIC_FAILURE, NULL, 0);
311 else
Wink Savillef4c4d362009-04-02 01:37:03 -0700312 RIL_onUnsolicitedResponse(RIL_UNSOL_DATA_CALL_LIST_CHANGED,
The Android Open Source Project00f06fc2009-03-03 19:32:15 -0800313 NULL, 0);
314 return;
315 }
316
317 for (p_cur = p_response->p_intermediates; p_cur != NULL;
318 p_cur = p_cur->p_next)
319 n++;
320
Wink Saville2c1fb3a2011-03-19 13:42:45 -0700321 RIL_Data_Call_Response_v6 *responses =
322 alloca(n * sizeof(RIL_Data_Call_Response_v6));
The Android Open Source Project00f06fc2009-03-03 19:32:15 -0800323
324 int i;
325 for (i = 0; i < n; i++) {
Wink Saville43808972011-01-13 17:39:51 -0800326 responses[i].status = -1;
Wink Saville250eb3c2011-06-22 09:11:34 -0700327 responses[i].suggestedRetryTime = -1;
The Android Open Source Project00f06fc2009-03-03 19:32:15 -0800328 responses[i].cid = -1;
329 responses[i].active = -1;
330 responses[i].type = "";
Wink Saville43808972011-01-13 17:39:51 -0800331 responses[i].ifname = "";
332 responses[i].addresses = "";
333 responses[i].dnses = "";
Wink Saville2c1fb3a2011-03-19 13:42:45 -0700334 responses[i].gateways = "";
The Android Open Source Project00f06fc2009-03-03 19:32:15 -0800335 }
336
Wink Saville2c1fb3a2011-03-19 13:42:45 -0700337 RIL_Data_Call_Response_v6 *response = responses;
The Android Open Source Project00f06fc2009-03-03 19:32:15 -0800338 for (p_cur = p_response->p_intermediates; p_cur != NULL;
339 p_cur = p_cur->p_next) {
340 char *line = p_cur->line;
341
342 err = at_tok_start(&line);
343 if (err < 0)
344 goto error;
345
346 err = at_tok_nextint(&line, &response->cid);
347 if (err < 0)
348 goto error;
349
350 err = at_tok_nextint(&line, &response->active);
351 if (err < 0)
352 goto error;
353
354 response++;
355 }
356
357 at_response_free(p_response);
358
359 err = at_send_command_multiline ("AT+CGDCONT?", "+CGDCONT:", &p_response);
360 if (err != 0 || p_response->success == 0) {
361 if (t != NULL)
362 RIL_onRequestComplete(*t, RIL_E_GENERIC_FAILURE, NULL, 0);
363 else
Wink Savillef4c4d362009-04-02 01:37:03 -0700364 RIL_onUnsolicitedResponse(RIL_UNSOL_DATA_CALL_LIST_CHANGED,
The Android Open Source Project00f06fc2009-03-03 19:32:15 -0800365 NULL, 0);
366 return;
367 }
368
369 for (p_cur = p_response->p_intermediates; p_cur != NULL;
370 p_cur = p_cur->p_next) {
371 char *line = p_cur->line;
372 int cid;
The Android Open Source Project00f06fc2009-03-03 19:32:15 -0800373
374 err = at_tok_start(&line);
375 if (err < 0)
376 goto error;
377
378 err = at_tok_nextint(&line, &cid);
379 if (err < 0)
380 goto error;
381
382 for (i = 0; i < n; i++) {
383 if (responses[i].cid == cid)
384 break;
385 }
386
387 if (i >= n) {
388 /* details for a context we didn't hear about in the last request */
389 continue;
390 }
391
Wink Saville43808972011-01-13 17:39:51 -0800392 // Assume no error
393 responses[i].status = 0;
394
395 // type
The Android Open Source Project00f06fc2009-03-03 19:32:15 -0800396 err = at_tok_nextstr(&line, &out);
397 if (err < 0)
398 goto error;
The Android Open Source Project00f06fc2009-03-03 19:32:15 -0800399 responses[i].type = alloca(strlen(out) + 1);
400 strcpy(responses[i].type, out);
401
Wink Saville43808972011-01-13 17:39:51 -0800402 // APN ignored for v5
The Android Open Source Project00f06fc2009-03-03 19:32:15 -0800403 err = at_tok_nextstr(&line, &out);
404 if (err < 0)
405 goto error;
406
Wink Saville43808972011-01-13 17:39:51 -0800407 responses[i].ifname = alloca(strlen(PPP_TTY_PATH) + 1);
408 strcpy(responses[i].ifname, PPP_TTY_PATH);
The Android Open Source Project00f06fc2009-03-03 19:32:15 -0800409
410 err = at_tok_nextstr(&line, &out);
411 if (err < 0)
412 goto error;
413
Wink Saville43808972011-01-13 17:39:51 -0800414 responses[i].addresses = alloca(strlen(out) + 1);
415 strcpy(responses[i].addresses, out);
416
David 'Digit' Turneraf1298d2011-02-04 13:36:47 +0100417 {
418 char propValue[PROP_VALUE_MAX];
419
420 if (__system_property_get("ro.kernel.qemu", propValue) != 0) {
421 /* We are in the emulator - the dns servers are listed
422 * by the following system properties, setup in
423 * /system/etc/init.goldfish.sh:
424 * - net.eth0.dns1
425 * - net.eth0.dns2
426 * - net.eth0.dns3
427 * - net.eth0.dns4
428 */
429 const int dnslist_sz = 128;
430 char* dnslist = alloca(dnslist_sz);
431 const char* separator = "";
432 int nn;
433
434 dnslist[0] = 0;
435 for (nn = 1; nn <= 4; nn++) {
436 /* Probe net.eth0.dns<n> */
437 char propName[PROP_NAME_MAX];
438 snprintf(propName, sizeof propName, "net.eth0.dns%d", nn);
439
440 /* Ignore if undefined */
441 if (__system_property_get(propName, propValue) == 0) {
442 continue;
443 }
444
445 /* Append the DNS IP address */
446 strlcat(dnslist, separator, dnslist_sz);
447 strlcat(dnslist, propValue, dnslist_sz);
448 separator = " ";
449 }
450 responses[i].dnses = dnslist;
Wink Saville2c1fb3a2011-03-19 13:42:45 -0700451
452 /* There is only on gateway in the emulator */
453 responses[i].gateways = "10.0.2.2";
David 'Digit' Turneraf1298d2011-02-04 13:36:47 +0100454 }
455 else {
456 /* I don't know where we are, so use the public Google DNS
Wink Saville2c1fb3a2011-03-19 13:42:45 -0700457 * servers by default and no gateway.
David 'Digit' Turneraf1298d2011-02-04 13:36:47 +0100458 */
459 responses[i].dnses = "8.8.8.8 8.8.4.4";
Wink Saville2c1fb3a2011-03-19 13:42:45 -0700460 responses[i].gateways = "";
David 'Digit' Turneraf1298d2011-02-04 13:36:47 +0100461 }
462 }
The Android Open Source Project00f06fc2009-03-03 19:32:15 -0800463 }
464
465 at_response_free(p_response);
466
467 if (t != NULL)
468 RIL_onRequestComplete(*t, RIL_E_SUCCESS, responses,
Wink Saville2c1fb3a2011-03-19 13:42:45 -0700469 n * sizeof(RIL_Data_Call_Response_v6));
The Android Open Source Project00f06fc2009-03-03 19:32:15 -0800470 else
Wink Savillef4c4d362009-04-02 01:37:03 -0700471 RIL_onUnsolicitedResponse(RIL_UNSOL_DATA_CALL_LIST_CHANGED,
The Android Open Source Project00f06fc2009-03-03 19:32:15 -0800472 responses,
Wink Saville2c1fb3a2011-03-19 13:42:45 -0700473 n * sizeof(RIL_Data_Call_Response_v6));
The Android Open Source Project00f06fc2009-03-03 19:32:15 -0800474
475 return;
476
477error:
478 if (t != NULL)
479 RIL_onRequestComplete(*t, RIL_E_GENERIC_FAILURE, NULL, 0);
480 else
Wink Savillef4c4d362009-04-02 01:37:03 -0700481 RIL_onUnsolicitedResponse(RIL_UNSOL_DATA_CALL_LIST_CHANGED,
The Android Open Source Project00f06fc2009-03-03 19:32:15 -0800482 NULL, 0);
483
484 at_response_free(p_response);
485}
486
487static void requestQueryNetworkSelectionMode(
488 void *data, size_t datalen, RIL_Token t)
489{
490 int err;
491 ATResponse *p_response = NULL;
492 int response = 0;
493 char *line;
494
495 err = at_send_command_singleline("AT+COPS?", "+COPS:", &p_response);
496
497 if (err < 0 || p_response->success == 0) {
498 goto error;
499 }
500
501 line = p_response->p_intermediates->line;
502
503 err = at_tok_start(&line);
504
505 if (err < 0) {
506 goto error;
507 }
508
509 err = at_tok_nextint(&line, &response);
510
511 if (err < 0) {
512 goto error;
513 }
514
515 RIL_onRequestComplete(t, RIL_E_SUCCESS, &response, sizeof(int));
516 at_response_free(p_response);
517 return;
518error:
519 at_response_free(p_response);
Steve Block170fbda2012-01-08 13:48:26 +0000520 ALOGE("requestQueryNetworkSelectionMode must never return error when radio is on");
The Android Open Source Project00f06fc2009-03-03 19:32:15 -0800521 RIL_onRequestComplete(t, RIL_E_GENERIC_FAILURE, NULL, 0);
522}
523
524static void sendCallStateChanged(void *param)
525{
526 RIL_onUnsolicitedResponse (
527 RIL_UNSOL_RESPONSE_CALL_STATE_CHANGED,
528 NULL, 0);
529}
530
531static void requestGetCurrentCalls(void *data, size_t datalen, RIL_Token t)
532{
533 int err;
534 ATResponse *p_response;
535 ATLine *p_cur;
536 int countCalls;
537 int countValidCalls;
Wink Saville3d54e742009-05-18 18:00:44 -0700538 RIL_Call *p_calls;
539 RIL_Call **pp_calls;
The Android Open Source Project00f06fc2009-03-03 19:32:15 -0800540 int i;
541 int needRepoll = 0;
542
543#ifdef WORKAROUND_ERRONEOUS_ANSWER
544 int prevIncomingOrWaitingLine;
545
546 prevIncomingOrWaitingLine = s_incomingOrWaitingLine;
547 s_incomingOrWaitingLine = -1;
548#endif /*WORKAROUND_ERRONEOUS_ANSWER*/
549
550 err = at_send_command_multiline ("AT+CLCC", "+CLCC:", &p_response);
551
552 if (err != 0 || p_response->success == 0) {
553 RIL_onRequestComplete(t, RIL_E_GENERIC_FAILURE, NULL, 0);
554 return;
555 }
556
557 /* count the calls */
558 for (countCalls = 0, p_cur = p_response->p_intermediates
559 ; p_cur != NULL
560 ; p_cur = p_cur->p_next
561 ) {
562 countCalls++;
563 }
564
565 /* yes, there's an array of pointers and then an array of structures */
566
Wink Saville3d54e742009-05-18 18:00:44 -0700567 pp_calls = (RIL_Call **)alloca(countCalls * sizeof(RIL_Call *));
568 p_calls = (RIL_Call *)alloca(countCalls * sizeof(RIL_Call));
569 memset (p_calls, 0, countCalls * sizeof(RIL_Call));
The Android Open Source Project00f06fc2009-03-03 19:32:15 -0800570
571 /* init the pointer array */
572 for(i = 0; i < countCalls ; i++) {
573 pp_calls[i] = &(p_calls[i]);
574 }
575
576 for (countValidCalls = 0, p_cur = p_response->p_intermediates
577 ; p_cur != NULL
578 ; p_cur = p_cur->p_next
579 ) {
580 err = callFromCLCCLine(p_cur->line, p_calls + countValidCalls);
581
582 if (err != 0) {
583 continue;
584 }
585
586#ifdef WORKAROUND_ERRONEOUS_ANSWER
587 if (p_calls[countValidCalls].state == RIL_CALL_INCOMING
588 || p_calls[countValidCalls].state == RIL_CALL_WAITING
589 ) {
590 s_incomingOrWaitingLine = p_calls[countValidCalls].index;
591 }
592#endif /*WORKAROUND_ERRONEOUS_ANSWER*/
593
594 if (p_calls[countValidCalls].state != RIL_CALL_ACTIVE
595 && p_calls[countValidCalls].state != RIL_CALL_HOLDING
596 ) {
597 needRepoll = 1;
598 }
599
600 countValidCalls++;
601 }
602
603#ifdef WORKAROUND_ERRONEOUS_ANSWER
604 // Basically:
605 // A call was incoming or waiting
606 // Now it's marked as active
607 // But we never answered it
608 //
609 // This is probably a bug, and the call will probably
610 // disappear from the call list in the next poll
611 if (prevIncomingOrWaitingLine >= 0
612 && s_incomingOrWaitingLine < 0
613 && s_expectAnswer == 0
614 ) {
615 for (i = 0; i < countValidCalls ; i++) {
616
617 if (p_calls[i].index == prevIncomingOrWaitingLine
618 && p_calls[i].state == RIL_CALL_ACTIVE
619 && s_repollCallsCount < REPOLL_CALLS_COUNT_MAX
620 ) {
Steve Blockb4e26162012-01-05 00:10:31 +0000621 ALOGI(
The Android Open Source Project00f06fc2009-03-03 19:32:15 -0800622 "Hit WORKAROUND_ERRONOUS_ANSWER case."
623 " Repoll count: %d\n", s_repollCallsCount);
624 s_repollCallsCount++;
625 goto error;
626 }
627 }
628 }
629
630 s_expectAnswer = 0;
631 s_repollCallsCount = 0;
632#endif /*WORKAROUND_ERRONEOUS_ANSWER*/
633
Wink Saville3d54e742009-05-18 18:00:44 -0700634 RIL_onRequestComplete(t, RIL_E_SUCCESS, pp_calls,
635 countValidCalls * sizeof (RIL_Call *));
The Android Open Source Project00f06fc2009-03-03 19:32:15 -0800636
637 at_response_free(p_response);
638
639#ifdef POLL_CALL_STATE
640 if (countValidCalls) { // We don't seem to get a "NO CARRIER" message from
641 // smd, so we're forced to poll until the call ends.
642#else
643 if (needRepoll) {
644#endif
645 RIL_requestTimedCallback (sendCallStateChanged, NULL, &TIMEVAL_CALLSTATEPOLL);
646 }
647
648 return;
649error:
650 RIL_onRequestComplete(t, RIL_E_GENERIC_FAILURE, NULL, 0);
651 at_response_free(p_response);
652}
653
654static void requestDial(void *data, size_t datalen, RIL_Token t)
655{
656 RIL_Dial *p_dial;
657 char *cmd;
658 const char *clir;
659 int ret;
660
661 p_dial = (RIL_Dial *)data;
662
663 switch (p_dial->clir) {
664 case 1: clir = "I"; break; /*invocation*/
665 case 2: clir = "i"; break; /*suppression*/
666 default:
667 case 0: clir = ""; break; /*subscription default*/
668 }
669
670 asprintf(&cmd, "ATD%s%s;", p_dial->address, clir);
671
672 ret = at_send_command(cmd, NULL);
673
674 free(cmd);
675
676 /* success or failure is ignored by the upper layer here.
677 it will call GET_CURRENT_CALLS and determine success that way */
678 RIL_onRequestComplete(t, RIL_E_SUCCESS, NULL, 0);
679}
680
681static void requestWriteSmsToSim(void *data, size_t datalen, RIL_Token t)
682{
683 RIL_SMS_WriteArgs *p_args;
684 char *cmd;
685 int length;
686 int err;
687 ATResponse *p_response = NULL;
688
689 p_args = (RIL_SMS_WriteArgs *)data;
690
691 length = strlen(p_args->pdu)/2;
692 asprintf(&cmd, "AT+CMGW=%d,%d", length, p_args->status);
693
694 err = at_send_command_sms(cmd, p_args->pdu, "+CMGW:", &p_response);
695
696 if (err != 0 || p_response->success == 0) goto error;
697
698 RIL_onRequestComplete(t, RIL_E_SUCCESS, NULL, 0);
699 at_response_free(p_response);
700
701 return;
702error:
703 RIL_onRequestComplete(t, RIL_E_GENERIC_FAILURE, NULL, 0);
704 at_response_free(p_response);
705}
706
707static void requestHangup(void *data, size_t datalen, RIL_Token t)
708{
709 int *p_line;
710
711 int ret;
712 char *cmd;
713
714 p_line = (int *)data;
715
716 // 3GPP 22.030 6.5.5
717 // "Releases a specific active call X"
718 asprintf(&cmd, "AT+CHLD=1%d", p_line[0]);
719
720 ret = at_send_command(cmd, NULL);
721
722 free(cmd);
723
724 /* success or failure is ignored by the upper layer here.
725 it will call GET_CURRENT_CALLS and determine success that way */
726 RIL_onRequestComplete(t, RIL_E_SUCCESS, NULL, 0);
727}
728
729static void requestSignalStrength(void *data, size_t datalen, RIL_Token t)
730{
Chih-Wei Huang28059052012-04-30 01:13:27 +0800731 RIL_SignalStrength_v6 response;
The Android Open Source Project00f06fc2009-03-03 19:32:15 -0800732 ATResponse *p_response = NULL;
733 int err;
The Android Open Source Project00f06fc2009-03-03 19:32:15 -0800734 char *line;
735
736 err = at_send_command_singleline("AT+CSQ", "+CSQ:", &p_response);
737
738 if (err < 0 || p_response->success == 0) {
739 RIL_onRequestComplete(t, RIL_E_GENERIC_FAILURE, NULL, 0);
740 goto error;
741 }
742
743 line = p_response->p_intermediates->line;
744
745 err = at_tok_start(&line);
746 if (err < 0) goto error;
747
Chih-Wei Huang28059052012-04-30 01:13:27 +0800748 memset(&response, 0, sizeof(RIL_SignalStrength_v6));
749
750 err = at_tok_nextint(&line, &response.GW_SignalStrength.signalStrength);
The Android Open Source Project00f06fc2009-03-03 19:32:15 -0800751 if (err < 0) goto error;
752
Chih-Wei Huang28059052012-04-30 01:13:27 +0800753 err = at_tok_nextint(&line, &response.GW_SignalStrength.bitErrorRate);
The Android Open Source Project00f06fc2009-03-03 19:32:15 -0800754 if (err < 0) goto error;
755
Chih-Wei Huang28059052012-04-30 01:13:27 +0800756 RIL_onRequestComplete(t, RIL_E_SUCCESS, &response, sizeof(response));
The Android Open Source Project00f06fc2009-03-03 19:32:15 -0800757
758 at_response_free(p_response);
759 return;
760
761error:
Steve Block170fbda2012-01-08 13:48:26 +0000762 ALOGE("requestSignalStrength must never return an error when radio is on");
The Android Open Source Project00f06fc2009-03-03 19:32:15 -0800763 RIL_onRequestComplete(t, RIL_E_GENERIC_FAILURE, NULL, 0);
764 at_response_free(p_response);
765}
766
767static void requestRegistrationState(int request, void *data,
768 size_t datalen, RIL_Token t)
769{
770 int err;
771 int response[4];
772 char * responseStr[4];
773 ATResponse *p_response = NULL;
774 const char *cmd;
775 const char *prefix;
776 char *line, *p;
777 int commas;
778 int skip;
779 int count = 3;
780
781
Wink Saville2c1fb3a2011-03-19 13:42:45 -0700782 if (request == RIL_REQUEST_VOICE_REGISTRATION_STATE) {
The Android Open Source Project00f06fc2009-03-03 19:32:15 -0800783 cmd = "AT+CREG?";
784 prefix = "+CREG:";
Wink Saville2c1fb3a2011-03-19 13:42:45 -0700785 } else if (request == RIL_REQUEST_DATA_REGISTRATION_STATE) {
The Android Open Source Project00f06fc2009-03-03 19:32:15 -0800786 cmd = "AT+CGREG?";
787 prefix = "+CGREG:";
788 } else {
789 assert(0);
790 goto error;
791 }
792
793 err = at_send_command_singleline(cmd, prefix, &p_response);
794
795 if (err != 0) goto error;
796
797 line = p_response->p_intermediates->line;
798
799 err = at_tok_start(&line);
800 if (err < 0) goto error;
801
802 /* Ok you have to be careful here
803 * The solicited version of the CREG response is
804 * +CREG: n, stat, [lac, cid]
805 * and the unsolicited version is
806 * +CREG: stat, [lac, cid]
807 * The <n> parameter is basically "is unsolicited creg on?"
808 * which it should always be
809 *
810 * Now we should normally get the solicited version here,
811 * but the unsolicited version could have snuck in
812 * so we have to handle both
813 *
814 * Also since the LAC and CID are only reported when registered,
815 * we can have 1, 2, 3, or 4 arguments here
816 *
817 * finally, a +CGREG: answer may have a fifth value that corresponds
818 * to the network type, as in;
819 *
820 * +CGREG: n, stat [,lac, cid [,networkType]]
821 */
822
823 /* count number of commas */
824 commas = 0;
825 for (p = line ; *p != '\0' ;p++) {
826 if (*p == ',') commas++;
827 }
828
829 switch (commas) {
830 case 0: /* +CREG: <stat> */
831 err = at_tok_nextint(&line, &response[0]);
832 if (err < 0) goto error;
833 response[1] = -1;
834 response[2] = -1;
835 break;
836
837 case 1: /* +CREG: <n>, <stat> */
838 err = at_tok_nextint(&line, &skip);
839 if (err < 0) goto error;
840 err = at_tok_nextint(&line, &response[0]);
841 if (err < 0) goto error;
842 response[1] = -1;
843 response[2] = -1;
844 if (err < 0) goto error;
845 break;
846
847 case 2: /* +CREG: <stat>, <lac>, <cid> */
848 err = at_tok_nextint(&line, &response[0]);
849 if (err < 0) goto error;
850 err = at_tok_nexthexint(&line, &response[1]);
851 if (err < 0) goto error;
852 err = at_tok_nexthexint(&line, &response[2]);
853 if (err < 0) goto error;
854 break;
855 case 3: /* +CREG: <n>, <stat>, <lac>, <cid> */
856 err = at_tok_nextint(&line, &skip);
857 if (err < 0) goto error;
858 err = at_tok_nextint(&line, &response[0]);
859 if (err < 0) goto error;
860 err = at_tok_nexthexint(&line, &response[1]);
861 if (err < 0) goto error;
862 err = at_tok_nexthexint(&line, &response[2]);
863 if (err < 0) goto error;
864 break;
865 /* special case for CGREG, there is a fourth parameter
866 * that is the network type (unknown/gprs/edge/umts)
867 */
868 case 4: /* +CGREG: <n>, <stat>, <lac>, <cid>, <networkType> */
869 err = at_tok_nextint(&line, &skip);
870 if (err < 0) goto error;
871 err = at_tok_nextint(&line, &response[0]);
872 if (err < 0) goto error;
873 err = at_tok_nexthexint(&line, &response[1]);
874 if (err < 0) goto error;
875 err = at_tok_nexthexint(&line, &response[2]);
876 if (err < 0) goto error;
877 err = at_tok_nexthexint(&line, &response[3]);
878 if (err < 0) goto error;
879 count = 4;
880 break;
881 default:
882 goto error;
883 }
884
885 asprintf(&responseStr[0], "%d", response[0]);
John Wang6f189a62009-06-30 13:12:53 -0700886 asprintf(&responseStr[1], "%x", response[1]);
887 asprintf(&responseStr[2], "%x", response[2]);
The Android Open Source Project00f06fc2009-03-03 19:32:15 -0800888
889 if (count > 3)
890 asprintf(&responseStr[3], "%d", response[3]);
891
892 RIL_onRequestComplete(t, RIL_E_SUCCESS, responseStr, count*sizeof(char*));
893 at_response_free(p_response);
894
895 return;
896error:
Steve Block170fbda2012-01-08 13:48:26 +0000897 ALOGE("requestRegistrationState must never return an error when radio is on");
The Android Open Source Project00f06fc2009-03-03 19:32:15 -0800898 RIL_onRequestComplete(t, RIL_E_GENERIC_FAILURE, NULL, 0);
899 at_response_free(p_response);
900}
901
902static void requestOperator(void *data, size_t datalen, RIL_Token t)
903{
904 int err;
905 int i;
906 int skip;
907 ATLine *p_cur;
908 char *response[3];
909
910 memset(response, 0, sizeof(response));
911
912 ATResponse *p_response = NULL;
913
914 err = at_send_command_multiline(
915 "AT+COPS=3,0;+COPS?;+COPS=3,1;+COPS?;+COPS=3,2;+COPS?",
916 "+COPS:", &p_response);
917
918 /* we expect 3 lines here:
919 * +COPS: 0,0,"T - Mobile"
920 * +COPS: 0,1,"TMO"
921 * +COPS: 0,2,"310170"
922 */
923
924 if (err != 0) goto error;
925
926 for (i = 0, p_cur = p_response->p_intermediates
927 ; p_cur != NULL
928 ; p_cur = p_cur->p_next, i++
929 ) {
930 char *line = p_cur->line;
931
932 err = at_tok_start(&line);
933 if (err < 0) goto error;
934
935 err = at_tok_nextint(&line, &skip);
936 if (err < 0) goto error;
937
938 // If we're unregistered, we may just get
939 // a "+COPS: 0" response
940 if (!at_tok_hasmore(&line)) {
941 response[i] = NULL;
942 continue;
943 }
944
945 err = at_tok_nextint(&line, &skip);
946 if (err < 0) goto error;
947
948 // a "+COPS: 0, n" response is also possible
949 if (!at_tok_hasmore(&line)) {
950 response[i] = NULL;
951 continue;
952 }
953
954 err = at_tok_nextstr(&line, &(response[i]));
955 if (err < 0) goto error;
956 }
957
958 if (i != 3) {
959 /* expect 3 lines exactly */
960 goto error;
961 }
962
963 RIL_onRequestComplete(t, RIL_E_SUCCESS, response, sizeof(response));
964 at_response_free(p_response);
965
966 return;
967error:
Steve Block170fbda2012-01-08 13:48:26 +0000968 ALOGE("requestOperator must not return error when radio is on");
The Android Open Source Project00f06fc2009-03-03 19:32:15 -0800969 RIL_onRequestComplete(t, RIL_E_GENERIC_FAILURE, NULL, 0);
970 at_response_free(p_response);
971}
972
973static void requestSendSMS(void *data, size_t datalen, RIL_Token t)
974{
975 int err;
976 const char *smsc;
977 const char *pdu;
978 int tpLayerLength;
979 char *cmd1, *cmd2;
980 RIL_SMS_Response response;
981 ATResponse *p_response = NULL;
982
983 smsc = ((const char **)data)[0];
984 pdu = ((const char **)data)[1];
985
986 tpLayerLength = strlen(pdu)/2;
987
988 // "NULL for default SMSC"
989 if (smsc == NULL) {
990 smsc= "00";
991 }
992
993 asprintf(&cmd1, "AT+CMGS=%d", tpLayerLength);
994 asprintf(&cmd2, "%s%s", smsc, pdu);
995
996 err = at_send_command_sms(cmd1, cmd2, "+CMGS:", &p_response);
997
998 if (err != 0 || p_response->success == 0) goto error;
999
1000 memset(&response, 0, sizeof(response));
1001
1002 /* FIXME fill in messageRef and ackPDU */
1003
1004 RIL_onRequestComplete(t, RIL_E_SUCCESS, &response, sizeof(response));
1005 at_response_free(p_response);
1006
1007 return;
1008error:
1009 RIL_onRequestComplete(t, RIL_E_GENERIC_FAILURE, NULL, 0);
1010 at_response_free(p_response);
1011}
1012
Wink Savillef4c4d362009-04-02 01:37:03 -07001013static void requestSetupDataCall(void *data, size_t datalen, RIL_Token t)
The Android Open Source Project00f06fc2009-03-03 19:32:15 -08001014{
1015 const char *apn;
1016 char *cmd;
1017 int err;
1018 ATResponse *p_response = NULL;
The Android Open Source Project00f06fc2009-03-03 19:32:15 -08001019
Wink Savillef4c4d362009-04-02 01:37:03 -07001020 apn = ((const char **)data)[2];
The Android Open Source Project00f06fc2009-03-03 19:32:15 -08001021
1022#ifdef USE_TI_COMMANDS
1023 // Config for multislot class 10 (probably default anyway eh?)
1024 err = at_send_command("AT%CPRIM=\"GMM\",\"CONFIG MULTISLOT_CLASS=<10>\"",
1025 NULL);
1026
1027 err = at_send_command("AT%DATA=2,\"UART\",1,,\"SER\",\"UART\",0", NULL);
1028#endif /* USE_TI_COMMANDS */
1029
1030 int fd, qmistatus;
1031 size_t cur = 0;
1032 size_t len;
1033 ssize_t written, rlen;
1034 char status[32] = {0};
1035 int retry = 10;
Lorenzo Colitti4f81dcf2010-09-01 19:38:57 -07001036 const char *pdp_type;
The Android Open Source Project00f06fc2009-03-03 19:32:15 -08001037
Steve Block20cd1142011-12-20 20:47:51 +00001038 ALOGD("requesting data connection to APN '%s'", apn);
The Android Open Source Project00f06fc2009-03-03 19:32:15 -08001039
1040 fd = open ("/dev/qmi", O_RDWR);
1041 if (fd >= 0) { /* the device doesn't exist on the emulator */
1042
Steve Block20cd1142011-12-20 20:47:51 +00001043 ALOGD("opened the qmi device\n");
Lorenzo Colitti4f81dcf2010-09-01 19:38:57 -07001044 asprintf(&cmd, "up:%s", apn);
1045 len = strlen(cmd);
The Android Open Source Project00f06fc2009-03-03 19:32:15 -08001046
Lorenzo Colitti4f81dcf2010-09-01 19:38:57 -07001047 while (cur < len) {
1048 do {
1049 written = write (fd, cmd + cur, len - cur);
1050 } while (written < 0 && errno == EINTR);
The Android Open Source Project00f06fc2009-03-03 19:32:15 -08001051
Lorenzo Colitti4f81dcf2010-09-01 19:38:57 -07001052 if (written < 0) {
Steve Block170fbda2012-01-08 13:48:26 +00001053 ALOGE("### ERROR writing to /dev/qmi");
The Android Open Source Project00f06fc2009-03-03 19:32:15 -08001054 close(fd);
1055 goto error;
1056 }
1057
1058 cur += written;
1059 }
1060
1061 // wait for interface to come online
1062
1063 do {
1064 sleep(1);
1065 do {
1066 rlen = read(fd, status, 31);
1067 } while (rlen < 0 && errno == EINTR);
1068
1069 if (rlen < 0) {
Steve Block170fbda2012-01-08 13:48:26 +00001070 ALOGE("### ERROR reading from /dev/qmi");
The Android Open Source Project00f06fc2009-03-03 19:32:15 -08001071 close(fd);
1072 goto error;
1073 } else {
1074 status[rlen] = '\0';
Steve Block20cd1142011-12-20 20:47:51 +00001075 ALOGD("### status: %s", status);
The Android Open Source Project00f06fc2009-03-03 19:32:15 -08001076 }
1077 } while (strncmp(status, "STATE=up", 8) && strcmp(status, "online") && --retry);
1078
1079 close(fd);
1080
1081 if (retry == 0) {
Steve Block170fbda2012-01-08 13:48:26 +00001082 ALOGE("### Failed to get data connection up\n");
Lorenzo Colitti4f81dcf2010-09-01 19:38:57 -07001083 goto error;
1084 }
The Android Open Source Project00f06fc2009-03-03 19:32:15 -08001085
1086 qmistatus = system("netcfg rmnet0 dhcp");
1087
Steve Block20cd1142011-12-20 20:47:51 +00001088 ALOGD("netcfg rmnet0 dhcp: status %d\n", qmistatus);
The Android Open Source Project00f06fc2009-03-03 19:32:15 -08001089
Lorenzo Colitti4f81dcf2010-09-01 19:38:57 -07001090 if (qmistatus < 0) goto error;
The Android Open Source Project00f06fc2009-03-03 19:32:15 -08001091
Lorenzo Colitti4f81dcf2010-09-01 19:38:57 -07001092 } else {
The Android Open Source Project00f06fc2009-03-03 19:32:15 -08001093
Lorenzo Colitti4f81dcf2010-09-01 19:38:57 -07001094 if (datalen > 6 * sizeof(char *)) {
1095 pdp_type = ((const char **)data)[6];
1096 } else {
1097 pdp_type = "IP";
1098 }
The Android Open Source Project00f06fc2009-03-03 19:32:15 -08001099
David 'Digit' Turneraf1298d2011-02-04 13:36:47 +01001100 asprintf(&cmd, "AT+CGDCONT=1,\"%s\",\"%s\",,0,0", pdp_type, apn);
Lorenzo Colitti4f81dcf2010-09-01 19:38:57 -07001101 //FIXME check for error here
1102 err = at_send_command(cmd, NULL);
1103 free(cmd);
The Android Open Source Project00f06fc2009-03-03 19:32:15 -08001104
Lorenzo Colitti4f81dcf2010-09-01 19:38:57 -07001105 // Set required QoS params to default
1106 err = at_send_command("AT+CGQREQ=1", NULL);
The Android Open Source Project00f06fc2009-03-03 19:32:15 -08001107
Lorenzo Colitti4f81dcf2010-09-01 19:38:57 -07001108 // Set minimum QoS params to default
1109 err = at_send_command("AT+CGQMIN=1", NULL);
The Android Open Source Project00f06fc2009-03-03 19:32:15 -08001110
Lorenzo Colitti4f81dcf2010-09-01 19:38:57 -07001111 // packet-domain event reporting
1112 err = at_send_command("AT+CGEREP=1,0", NULL);
The Android Open Source Project00f06fc2009-03-03 19:32:15 -08001113
Lorenzo Colitti4f81dcf2010-09-01 19:38:57 -07001114 // Hangup anything that's happening there now
1115 err = at_send_command("AT+CGACT=1,0", NULL);
The Android Open Source Project00f06fc2009-03-03 19:32:15 -08001116
Lorenzo Colitti4f81dcf2010-09-01 19:38:57 -07001117 // Start data on PDP context 1
1118 err = at_send_command("ATD*99***1#", &p_response);
1119
1120 if (err < 0 || p_response->success == 0) {
1121 goto error;
1122 }
The Android Open Source Project00f06fc2009-03-03 19:32:15 -08001123 }
1124
Wink Saville43808972011-01-13 17:39:51 -08001125 requestOrSendDataCallList(&t);
1126
The Android Open Source Project00f06fc2009-03-03 19:32:15 -08001127 at_response_free(p_response);
1128
1129 return;
1130error:
1131 RIL_onRequestComplete(t, RIL_E_GENERIC_FAILURE, NULL, 0);
1132 at_response_free(p_response);
1133
1134}
1135
1136static void requestSMSAcknowledge(void *data, size_t datalen, RIL_Token t)
1137{
1138 int ackSuccess;
1139 int err;
1140
1141 ackSuccess = ((int *)data)[0];
1142
1143 if (ackSuccess == 1) {
1144 err = at_send_command("AT+CNMA=1", NULL);
1145 } else if (ackSuccess == 0) {
1146 err = at_send_command("AT+CNMA=2", NULL);
1147 } else {
Steve Block170fbda2012-01-08 13:48:26 +00001148 ALOGE("unsupported arg to RIL_REQUEST_SMS_ACKNOWLEDGE\n");
The Android Open Source Project00f06fc2009-03-03 19:32:15 -08001149 goto error;
1150 }
1151
1152 RIL_onRequestComplete(t, RIL_E_SUCCESS, NULL, 0);
1153error:
1154 RIL_onRequestComplete(t, RIL_E_GENERIC_FAILURE, NULL, 0);
1155
1156}
1157
1158static void requestSIM_IO(void *data, size_t datalen, RIL_Token t)
1159{
1160 ATResponse *p_response = NULL;
1161 RIL_SIM_IO_Response sr;
1162 int err;
1163 char *cmd = NULL;
Wink Saville2c1fb3a2011-03-19 13:42:45 -07001164 RIL_SIM_IO_v6 *p_args;
The Android Open Source Project00f06fc2009-03-03 19:32:15 -08001165 char *line;
1166
1167 memset(&sr, 0, sizeof(sr));
1168
Wink Saville2c1fb3a2011-03-19 13:42:45 -07001169 p_args = (RIL_SIM_IO_v6 *)data;
The Android Open Source Project00f06fc2009-03-03 19:32:15 -08001170
1171 /* FIXME handle pin2 */
1172
1173 if (p_args->data == NULL) {
1174 asprintf(&cmd, "AT+CRSM=%d,%d,%d,%d,%d",
1175 p_args->command, p_args->fileid,
1176 p_args->p1, p_args->p2, p_args->p3);
1177 } else {
1178 asprintf(&cmd, "AT+CRSM=%d,%d,%d,%d,%d,%s",
1179 p_args->command, p_args->fileid,
1180 p_args->p1, p_args->p2, p_args->p3, p_args->data);
1181 }
1182
1183 err = at_send_command_singleline(cmd, "+CRSM:", &p_response);
1184
1185 if (err < 0 || p_response->success == 0) {
1186 goto error;
1187 }
1188
1189 line = p_response->p_intermediates->line;
1190
1191 err = at_tok_start(&line);
1192 if (err < 0) goto error;
1193
1194 err = at_tok_nextint(&line, &(sr.sw1));
1195 if (err < 0) goto error;
1196
1197 err = at_tok_nextint(&line, &(sr.sw2));
1198 if (err < 0) goto error;
1199
1200 if (at_tok_hasmore(&line)) {
1201 err = at_tok_nextstr(&line, &(sr.simResponse));
1202 if (err < 0) goto error;
1203 }
1204
1205 RIL_onRequestComplete(t, RIL_E_SUCCESS, &sr, sizeof(sr));
1206 at_response_free(p_response);
1207 free(cmd);
1208
1209 return;
1210error:
1211 RIL_onRequestComplete(t, RIL_E_GENERIC_FAILURE, NULL, 0);
1212 at_response_free(p_response);
1213 free(cmd);
1214
1215}
1216
1217static void requestEnterSimPin(void* data, size_t datalen, RIL_Token t)
1218{
1219 ATResponse *p_response = NULL;
1220 int err;
1221 char* cmd = NULL;
1222 const char** strings = (const char**)data;;
1223
1224 if ( datalen == sizeof(char*) ) {
1225 asprintf(&cmd, "AT+CPIN=%s", strings[0]);
1226 } else if ( datalen == 2*sizeof(char*) ) {
1227 asprintf(&cmd, "AT+CPIN=%s,%s", strings[0], strings[1]);
1228 } else
1229 goto error;
1230
1231 err = at_send_command_singleline(cmd, "+CPIN:", &p_response);
1232 free(cmd);
1233
1234 if (err < 0 || p_response->success == 0) {
1235error:
1236 RIL_onRequestComplete(t, RIL_E_PASSWORD_INCORRECT, NULL, 0);
1237 } else {
1238 RIL_onRequestComplete(t, RIL_E_SUCCESS, NULL, 0);
1239 }
1240 at_response_free(p_response);
1241}
1242
1243
1244static void requestSendUSSD(void *data, size_t datalen, RIL_Token t)
1245{
1246 const char *ussdRequest;
1247
1248 ussdRequest = (char *)(data);
1249
1250
1251 RIL_onRequestComplete(t, RIL_E_REQUEST_NOT_SUPPORTED, NULL, 0);
1252
1253// @@@ TODO
1254
1255}
1256
1257
1258/*** Callback methods from the RIL library to us ***/
1259
1260/**
1261 * Call from RIL to us to make a RIL_REQUEST
1262 *
1263 * Must be completed with a call to RIL_onRequestComplete()
1264 *
1265 * RIL_onRequestComplete() may be called from any thread, before or after
1266 * this function returns.
1267 *
1268 * Will always be called from the same thread, so returning here implies
1269 * that the radio is ready to process another command (whether or not
1270 * the previous command has completed).
1271 */
1272static void
1273onRequest (int request, void *data, size_t datalen, RIL_Token t)
1274{
1275 ATResponse *p_response;
1276 int err;
1277
Steve Block20cd1142011-12-20 20:47:51 +00001278 ALOGD("onRequest: %s", requestToString(request));
The Android Open Source Project00f06fc2009-03-03 19:32:15 -08001279
1280 /* Ignore all requests except RIL_REQUEST_GET_SIM_STATUS
1281 * when RADIO_STATE_UNAVAILABLE.
1282 */
1283 if (sState == RADIO_STATE_UNAVAILABLE
1284 && request != RIL_REQUEST_GET_SIM_STATUS
1285 ) {
1286 RIL_onRequestComplete(t, RIL_E_RADIO_NOT_AVAILABLE, NULL, 0);
1287 return;
1288 }
1289
1290 /* Ignore all non-power requests when RADIO_STATE_OFF
1291 * (except RIL_REQUEST_GET_SIM_STATUS)
1292 */
1293 if (sState == RADIO_STATE_OFF
1294 && !(request == RIL_REQUEST_RADIO_POWER
1295 || request == RIL_REQUEST_GET_SIM_STATUS)
1296 ) {
1297 RIL_onRequestComplete(t, RIL_E_RADIO_NOT_AVAILABLE, NULL, 0);
1298 return;
1299 }
1300
1301 switch (request) {
1302 case RIL_REQUEST_GET_SIM_STATUS: {
Wink Saville2c1fb3a2011-03-19 13:42:45 -07001303 RIL_CardStatus_v6 *p_card_status;
Wink Savillef6aa7c12009-04-30 14:20:52 -07001304 char *p_buffer;
1305 int buffer_size;
The Android Open Source Project00f06fc2009-03-03 19:32:15 -08001306
Wink Savillef6aa7c12009-04-30 14:20:52 -07001307 int result = getCardStatus(&p_card_status);
1308 if (result == RIL_E_SUCCESS) {
1309 p_buffer = (char *)p_card_status;
1310 buffer_size = sizeof(*p_card_status);
1311 } else {
1312 p_buffer = NULL;
1313 buffer_size = 0;
1314 }
1315 RIL_onRequestComplete(t, result, p_buffer, buffer_size);
1316 freeCardStatus(p_card_status);
The Android Open Source Project00f06fc2009-03-03 19:32:15 -08001317 break;
1318 }
1319 case RIL_REQUEST_GET_CURRENT_CALLS:
1320 requestGetCurrentCalls(data, datalen, t);
1321 break;
1322 case RIL_REQUEST_DIAL:
1323 requestDial(data, datalen, t);
1324 break;
1325 case RIL_REQUEST_HANGUP:
1326 requestHangup(data, datalen, t);
1327 break;
1328 case RIL_REQUEST_HANGUP_WAITING_OR_BACKGROUND:
1329 // 3GPP 22.030 6.5.5
1330 // "Releases all held calls or sets User Determined User Busy
1331 // (UDUB) for a waiting call."
1332 at_send_command("AT+CHLD=0", NULL);
1333
1334 /* success or failure is ignored by the upper layer here.
1335 it will call GET_CURRENT_CALLS and determine success that way */
1336 RIL_onRequestComplete(t, RIL_E_SUCCESS, NULL, 0);
1337 break;
1338 case RIL_REQUEST_HANGUP_FOREGROUND_RESUME_BACKGROUND:
1339 // 3GPP 22.030 6.5.5
1340 // "Releases all active calls (if any exist) and accepts
1341 // the other (held or waiting) call."
1342 at_send_command("AT+CHLD=1", NULL);
1343
1344 /* success or failure is ignored by the upper layer here.
1345 it will call GET_CURRENT_CALLS and determine success that way */
1346 RIL_onRequestComplete(t, RIL_E_SUCCESS, NULL, 0);
1347 break;
1348 case RIL_REQUEST_SWITCH_WAITING_OR_HOLDING_AND_ACTIVE:
1349 // 3GPP 22.030 6.5.5
1350 // "Places all active calls (if any exist) on hold and accepts
1351 // the other (held or waiting) call."
1352 at_send_command("AT+CHLD=2", NULL);
1353
1354#ifdef WORKAROUND_ERRONEOUS_ANSWER
1355 s_expectAnswer = 1;
1356#endif /* WORKAROUND_ERRONEOUS_ANSWER */
1357
1358 /* success or failure is ignored by the upper layer here.
1359 it will call GET_CURRENT_CALLS and determine success that way */
1360 RIL_onRequestComplete(t, RIL_E_SUCCESS, NULL, 0);
1361 break;
1362 case RIL_REQUEST_ANSWER:
1363 at_send_command("ATA", NULL);
1364
1365#ifdef WORKAROUND_ERRONEOUS_ANSWER
1366 s_expectAnswer = 1;
1367#endif /* WORKAROUND_ERRONEOUS_ANSWER */
1368
1369 /* success or failure is ignored by the upper layer here.
1370 it will call GET_CURRENT_CALLS and determine success that way */
1371 RIL_onRequestComplete(t, RIL_E_SUCCESS, NULL, 0);
1372 break;
1373 case RIL_REQUEST_CONFERENCE:
1374 // 3GPP 22.030 6.5.5
1375 // "Adds a held call to the conversation"
1376 at_send_command("AT+CHLD=3", NULL);
1377
1378 /* success or failure is ignored by the upper layer here.
1379 it will call GET_CURRENT_CALLS and determine success that way */
1380 RIL_onRequestComplete(t, RIL_E_SUCCESS, NULL, 0);
1381 break;
1382 case RIL_REQUEST_UDUB:
1383 /* user determined user busy */
1384 /* sometimes used: ATH */
1385 at_send_command("ATH", NULL);
1386
1387 /* success or failure is ignored by the upper layer here.
1388 it will call GET_CURRENT_CALLS and determine success that way */
1389 RIL_onRequestComplete(t, RIL_E_SUCCESS, NULL, 0);
1390 break;
1391
1392 case RIL_REQUEST_SEPARATE_CONNECTION:
1393 {
1394 char cmd[12];
1395 int party = ((int*)data)[0];
1396
1397 // Make sure that party is in a valid range.
1398 // (Note: The Telephony middle layer imposes a range of 1 to 7.
1399 // It's sufficient for us to just make sure it's single digit.)
1400 if (party > 0 && party < 10) {
1401 sprintf(cmd, "AT+CHLD=2%d", party);
1402 at_send_command(cmd, NULL);
1403 RIL_onRequestComplete(t, RIL_E_SUCCESS, NULL, 0);
1404 } else {
1405 RIL_onRequestComplete(t, RIL_E_GENERIC_FAILURE, NULL, 0);
1406 }
1407 }
1408 break;
1409
1410 case RIL_REQUEST_SIGNAL_STRENGTH:
1411 requestSignalStrength(data, datalen, t);
1412 break;
Wink Saville2c1fb3a2011-03-19 13:42:45 -07001413 case RIL_REQUEST_VOICE_REGISTRATION_STATE:
1414 case RIL_REQUEST_DATA_REGISTRATION_STATE:
The Android Open Source Project00f06fc2009-03-03 19:32:15 -08001415 requestRegistrationState(request, data, datalen, t);
1416 break;
1417 case RIL_REQUEST_OPERATOR:
1418 requestOperator(data, datalen, t);
1419 break;
1420 case RIL_REQUEST_RADIO_POWER:
1421 requestRadioPower(data, datalen, t);
1422 break;
1423 case RIL_REQUEST_DTMF: {
1424 char c = ((char *)data)[0];
1425 char *cmd;
1426 asprintf(&cmd, "AT+VTS=%c", (int)c);
1427 at_send_command(cmd, NULL);
1428 free(cmd);
1429 RIL_onRequestComplete(t, RIL_E_SUCCESS, NULL, 0);
1430 break;
1431 }
1432 case RIL_REQUEST_SEND_SMS:
1433 requestSendSMS(data, datalen, t);
1434 break;
Wink Savillef4c4d362009-04-02 01:37:03 -07001435 case RIL_REQUEST_SETUP_DATA_CALL:
1436 requestSetupDataCall(data, datalen, t);
The Android Open Source Project00f06fc2009-03-03 19:32:15 -08001437 break;
1438 case RIL_REQUEST_SMS_ACKNOWLEDGE:
1439 requestSMSAcknowledge(data, datalen, t);
1440 break;
1441
1442 case RIL_REQUEST_GET_IMSI:
1443 p_response = NULL;
1444 err = at_send_command_numeric("AT+CIMI", &p_response);
1445
1446 if (err < 0 || p_response->success == 0) {
1447 RIL_onRequestComplete(t, RIL_E_GENERIC_FAILURE, NULL, 0);
1448 } else {
1449 RIL_onRequestComplete(t, RIL_E_SUCCESS,
1450 p_response->p_intermediates->line, sizeof(char *));
1451 }
1452 at_response_free(p_response);
1453 break;
1454
1455 case RIL_REQUEST_GET_IMEI:
1456 p_response = NULL;
1457 err = at_send_command_numeric("AT+CGSN", &p_response);
1458
1459 if (err < 0 || p_response->success == 0) {
1460 RIL_onRequestComplete(t, RIL_E_GENERIC_FAILURE, NULL, 0);
1461 } else {
1462 RIL_onRequestComplete(t, RIL_E_SUCCESS,
1463 p_response->p_intermediates->line, sizeof(char *));
1464 }
1465 at_response_free(p_response);
1466 break;
1467
1468 case RIL_REQUEST_SIM_IO:
1469 requestSIM_IO(data,datalen,t);
1470 break;
1471
1472 case RIL_REQUEST_SEND_USSD:
1473 requestSendUSSD(data, datalen, t);
1474 break;
1475
1476 case RIL_REQUEST_CANCEL_USSD:
1477 p_response = NULL;
1478 err = at_send_command_numeric("AT+CUSD=2", &p_response);
1479
1480 if (err < 0 || p_response->success == 0) {
1481 RIL_onRequestComplete(t, RIL_E_GENERIC_FAILURE, NULL, 0);
1482 } else {
1483 RIL_onRequestComplete(t, RIL_E_SUCCESS,
1484 p_response->p_intermediates->line, sizeof(char *));
1485 }
1486 at_response_free(p_response);
1487 break;
1488
1489 case RIL_REQUEST_SET_NETWORK_SELECTION_AUTOMATIC:
1490 at_send_command("AT+COPS=0", NULL);
1491 break;
1492
Wink Savillef4c4d362009-04-02 01:37:03 -07001493 case RIL_REQUEST_DATA_CALL_LIST:
1494 requestDataCallList(data, datalen, t);
The Android Open Source Project00f06fc2009-03-03 19:32:15 -08001495 break;
1496
1497 case RIL_REQUEST_QUERY_NETWORK_SELECTION_MODE:
1498 requestQueryNetworkSelectionMode(data, datalen, t);
1499 break;
1500
1501 case RIL_REQUEST_OEM_HOOK_RAW:
1502 // echo back data
1503 RIL_onRequestComplete(t, RIL_E_SUCCESS, data, datalen);
1504 break;
1505
1506
1507 case RIL_REQUEST_OEM_HOOK_STRINGS: {
1508 int i;
1509 const char ** cur;
1510
Steve Block20cd1142011-12-20 20:47:51 +00001511 ALOGD("got OEM_HOOK_STRINGS: 0x%8p %lu", data, (long)datalen);
The Android Open Source Project00f06fc2009-03-03 19:32:15 -08001512
1513
1514 for (i = (datalen / sizeof (char *)), cur = (const char **)data ;
1515 i > 0 ; cur++, i --) {
Steve Block20cd1142011-12-20 20:47:51 +00001516 ALOGD("> '%s'", *cur);
The Android Open Source Project00f06fc2009-03-03 19:32:15 -08001517 }
1518
1519 // echo back strings
1520 RIL_onRequestComplete(t, RIL_E_SUCCESS, data, datalen);
1521 break;
1522 }
1523
1524 case RIL_REQUEST_WRITE_SMS_TO_SIM:
1525 requestWriteSmsToSim(data, datalen, t);
1526 break;
1527
1528 case RIL_REQUEST_DELETE_SMS_ON_SIM: {
1529 char * cmd;
1530 p_response = NULL;
1531 asprintf(&cmd, "AT+CMGD=%d", ((int *)data)[0]);
1532 err = at_send_command(cmd, &p_response);
1533 free(cmd);
1534 if (err < 0 || p_response->success == 0) {
1535 RIL_onRequestComplete(t, RIL_E_GENERIC_FAILURE, NULL, 0);
1536 } else {
1537 RIL_onRequestComplete(t, RIL_E_SUCCESS, NULL, 0);
1538 }
1539 at_response_free(p_response);
1540 break;
1541 }
1542
1543 case RIL_REQUEST_ENTER_SIM_PIN:
1544 case RIL_REQUEST_ENTER_SIM_PUK:
1545 case RIL_REQUEST_ENTER_SIM_PIN2:
1546 case RIL_REQUEST_ENTER_SIM_PUK2:
1547 case RIL_REQUEST_CHANGE_SIM_PIN:
1548 case RIL_REQUEST_CHANGE_SIM_PIN2:
1549 requestEnterSimPin(data, datalen, t);
1550 break;
1551
1552 default:
1553 RIL_onRequestComplete(t, RIL_E_REQUEST_NOT_SUPPORTED, NULL, 0);
1554 break;
1555 }
1556}
1557
1558/**
1559 * Synchronous call from the RIL to us to return current radio state.
1560 * RADIO_STATE_UNAVAILABLE should be the initial state.
1561 */
1562static RIL_RadioState
1563currentState()
1564{
1565 return sState;
1566}
1567/**
1568 * Call from RIL to us to find out whether a specific request code
1569 * is supported by this implementation.
1570 *
1571 * Return 1 for "supported" and 0 for "unsupported"
1572 */
1573
1574static int
1575onSupports (int requestCode)
1576{
1577 //@@@ todo
1578
1579 return 1;
1580}
1581
1582static void onCancel (RIL_Token t)
1583{
1584 //@@@todo
1585
1586}
1587
1588static const char * getVersion(void)
1589{
1590 return "android reference-ril 1.0";
1591}
1592
1593static void
1594setRadioState(RIL_RadioState newState)
1595{
1596 RIL_RadioState oldState;
1597
1598 pthread_mutex_lock(&s_state_mutex);
1599
1600 oldState = sState;
1601
1602 if (s_closed > 0) {
1603 // If we're closed, the only reasonable state is
1604 // RADIO_STATE_UNAVAILABLE
1605 // This is here because things on the main thread
1606 // may attempt to change the radio state after the closed
1607 // event happened in another thread
1608 newState = RADIO_STATE_UNAVAILABLE;
1609 }
1610
1611 if (sState != newState || s_closed > 0) {
1612 sState = newState;
1613
1614 pthread_cond_broadcast (&s_state_cond);
1615 }
1616
1617 pthread_mutex_unlock(&s_state_mutex);
1618
1619
1620 /* do these outside of the mutex */
1621 if (sState != oldState) {
1622 RIL_onUnsolicitedResponse (RIL_UNSOL_RESPONSE_RADIO_STATE_CHANGED,
1623 NULL, 0);
1624
1625 /* FIXME onSimReady() and onRadioPowerOn() cannot be called
1626 * from the AT reader thread
1627 * Currently, this doesn't happen, but if that changes then these
1628 * will need to be dispatched on the request thread
1629 */
1630 if (sState == RADIO_STATE_SIM_READY) {
1631 onSIMReady();
1632 } else if (sState == RADIO_STATE_SIM_NOT_READY) {
1633 onRadioPowerOn();
1634 }
1635 }
1636}
1637
John Wang309ac292009-07-30 14:53:23 -07001638/** Returns SIM_NOT_READY on error */
David 'Digit' Turneraf1298d2011-02-04 13:36:47 +01001639static SIM_Status
The Android Open Source Project00f06fc2009-03-03 19:32:15 -08001640getSIMStatus()
1641{
1642 ATResponse *p_response = NULL;
1643 int err;
1644 int ret;
1645 char *cpinLine;
1646 char *cpinResult;
1647
1648 if (sState == RADIO_STATE_OFF || sState == RADIO_STATE_UNAVAILABLE) {
John Wang309ac292009-07-30 14:53:23 -07001649 ret = SIM_NOT_READY;
The Android Open Source Project00f06fc2009-03-03 19:32:15 -08001650 goto done;
1651 }
1652
1653 err = at_send_command_singleline("AT+CPIN?", "+CPIN:", &p_response);
1654
1655 if (err != 0) {
John Wang309ac292009-07-30 14:53:23 -07001656 ret = SIM_NOT_READY;
The Android Open Source Project00f06fc2009-03-03 19:32:15 -08001657 goto done;
1658 }
1659
1660 switch (at_get_cme_error(p_response)) {
1661 case CME_SUCCESS:
1662 break;
1663
1664 case CME_SIM_NOT_INSERTED:
John Wang309ac292009-07-30 14:53:23 -07001665 ret = SIM_ABSENT;
The Android Open Source Project00f06fc2009-03-03 19:32:15 -08001666 goto done;
1667
1668 default:
John Wang309ac292009-07-30 14:53:23 -07001669 ret = SIM_NOT_READY;
The Android Open Source Project00f06fc2009-03-03 19:32:15 -08001670 goto done;
1671 }
1672
1673 /* CPIN? has succeeded, now look at the result */
1674
1675 cpinLine = p_response->p_intermediates->line;
1676 err = at_tok_start (&cpinLine);
1677
1678 if (err < 0) {
John Wang309ac292009-07-30 14:53:23 -07001679 ret = SIM_NOT_READY;
The Android Open Source Project00f06fc2009-03-03 19:32:15 -08001680 goto done;
1681 }
1682
1683 err = at_tok_nextstr(&cpinLine, &cpinResult);
1684
1685 if (err < 0) {
John Wang309ac292009-07-30 14:53:23 -07001686 ret = SIM_NOT_READY;
The Android Open Source Project00f06fc2009-03-03 19:32:15 -08001687 goto done;
1688 }
1689
1690 if (0 == strcmp (cpinResult, "SIM PIN")) {
John Wang309ac292009-07-30 14:53:23 -07001691 ret = SIM_PIN;
The Android Open Source Project00f06fc2009-03-03 19:32:15 -08001692 goto done;
1693 } else if (0 == strcmp (cpinResult, "SIM PUK")) {
John Wang309ac292009-07-30 14:53:23 -07001694 ret = SIM_PUK;
The Android Open Source Project00f06fc2009-03-03 19:32:15 -08001695 goto done;
1696 } else if (0 == strcmp (cpinResult, "PH-NET PIN")) {
John Wang309ac292009-07-30 14:53:23 -07001697 return SIM_NETWORK_PERSONALIZATION;
The Android Open Source Project00f06fc2009-03-03 19:32:15 -08001698 } else if (0 != strcmp (cpinResult, "READY")) {
1699 /* we're treating unsupported lock types as "sim absent" */
John Wang309ac292009-07-30 14:53:23 -07001700 ret = SIM_ABSENT;
The Android Open Source Project00f06fc2009-03-03 19:32:15 -08001701 goto done;
1702 }
1703
1704 at_response_free(p_response);
1705 p_response = NULL;
1706 cpinResult = NULL;
1707
John Wang309ac292009-07-30 14:53:23 -07001708 ret = SIM_READY;
The Android Open Source Project00f06fc2009-03-03 19:32:15 -08001709
1710done:
1711 at_response_free(p_response);
1712 return ret;
1713}
1714
1715
1716/**
Wink Savillef6aa7c12009-04-30 14:20:52 -07001717 * Get the current card status.
1718 *
1719 * This must be freed using freeCardStatus.
1720 * @return: On success returns RIL_E_SUCCESS
1721 */
Wink Saville2c1fb3a2011-03-19 13:42:45 -07001722static int getCardStatus(RIL_CardStatus_v6 **pp_card_status) {
Wink Savillef6aa7c12009-04-30 14:20:52 -07001723 static RIL_AppStatus app_status_array[] = {
John Wang309ac292009-07-30 14:53:23 -07001724 // SIM_ABSENT = 0
Wink Savillef6aa7c12009-04-30 14:20:52 -07001725 { RIL_APPTYPE_UNKNOWN, RIL_APPSTATE_UNKNOWN, RIL_PERSOSUBSTATE_UNKNOWN,
1726 NULL, NULL, 0, RIL_PINSTATE_UNKNOWN, RIL_PINSTATE_UNKNOWN },
John Wang309ac292009-07-30 14:53:23 -07001727 // SIM_NOT_READY = 1
Wink Savillef6aa7c12009-04-30 14:20:52 -07001728 { RIL_APPTYPE_SIM, RIL_APPSTATE_DETECTED, RIL_PERSOSUBSTATE_UNKNOWN,
1729 NULL, NULL, 0, RIL_PINSTATE_UNKNOWN, RIL_PINSTATE_UNKNOWN },
John Wang309ac292009-07-30 14:53:23 -07001730 // SIM_READY = 2
Wink Savillef6aa7c12009-04-30 14:20:52 -07001731 { RIL_APPTYPE_SIM, RIL_APPSTATE_READY, RIL_PERSOSUBSTATE_READY,
1732 NULL, NULL, 0, RIL_PINSTATE_UNKNOWN, RIL_PINSTATE_UNKNOWN },
John Wang309ac292009-07-30 14:53:23 -07001733 // SIM_PIN = 3
Wink Savillef6aa7c12009-04-30 14:20:52 -07001734 { RIL_APPTYPE_SIM, RIL_APPSTATE_PIN, RIL_PERSOSUBSTATE_UNKNOWN,
1735 NULL, NULL, 0, RIL_PINSTATE_ENABLED_NOT_VERIFIED, RIL_PINSTATE_UNKNOWN },
John Wang309ac292009-07-30 14:53:23 -07001736 // SIM_PUK = 4
Wink Savillef6aa7c12009-04-30 14:20:52 -07001737 { RIL_APPTYPE_SIM, RIL_APPSTATE_PUK, RIL_PERSOSUBSTATE_UNKNOWN,
1738 NULL, NULL, 0, RIL_PINSTATE_ENABLED_BLOCKED, RIL_PINSTATE_UNKNOWN },
John Wang309ac292009-07-30 14:53:23 -07001739 // SIM_NETWORK_PERSONALIZATION = 5
Wink Savillef6aa7c12009-04-30 14:20:52 -07001740 { RIL_APPTYPE_SIM, RIL_APPSTATE_SUBSCRIPTION_PERSO, RIL_PERSOSUBSTATE_SIM_NETWORK,
1741 NULL, NULL, 0, RIL_PINSTATE_ENABLED_NOT_VERIFIED, RIL_PINSTATE_UNKNOWN }
1742 };
1743 RIL_CardState card_state;
1744 int num_apps;
1745
1746 int sim_status = getSIMStatus();
John Wang309ac292009-07-30 14:53:23 -07001747 if (sim_status == SIM_ABSENT) {
Wink Savillef6aa7c12009-04-30 14:20:52 -07001748 card_state = RIL_CARDSTATE_ABSENT;
1749 num_apps = 0;
1750 } else {
1751 card_state = RIL_CARDSTATE_PRESENT;
1752 num_apps = 1;
1753 }
1754
1755 // Allocate and initialize base card status.
Wink Saville2c1fb3a2011-03-19 13:42:45 -07001756 RIL_CardStatus_v6 *p_card_status = malloc(sizeof(RIL_CardStatus_v6));
Wink Savillef6aa7c12009-04-30 14:20:52 -07001757 p_card_status->card_state = card_state;
1758 p_card_status->universal_pin_state = RIL_PINSTATE_UNKNOWN;
1759 p_card_status->gsm_umts_subscription_app_index = RIL_CARD_MAX_APPS;
1760 p_card_status->cdma_subscription_app_index = RIL_CARD_MAX_APPS;
Wink Saville2c1fb3a2011-03-19 13:42:45 -07001761 p_card_status->ims_subscription_app_index = RIL_CARD_MAX_APPS;
Wink Savillef6aa7c12009-04-30 14:20:52 -07001762 p_card_status->num_applications = num_apps;
1763
1764 // Initialize application status
1765 int i;
1766 for (i = 0; i < RIL_CARD_MAX_APPS; i++) {
John Wang309ac292009-07-30 14:53:23 -07001767 p_card_status->applications[i] = app_status_array[SIM_ABSENT];
Wink Savillef6aa7c12009-04-30 14:20:52 -07001768 }
1769
1770 // Pickup the appropriate application status
1771 // that reflects sim_status for gsm.
1772 if (num_apps != 0) {
1773 // Only support one app, gsm
1774 p_card_status->num_applications = 1;
1775 p_card_status->gsm_umts_subscription_app_index = 0;
1776
1777 // Get the correct app status
1778 p_card_status->applications[0] = app_status_array[sim_status];
1779 }
1780
1781 *pp_card_status = p_card_status;
1782 return RIL_E_SUCCESS;
1783}
1784
1785/**
1786 * Free the card status returned by getCardStatus
1787 */
Wink Saville2c1fb3a2011-03-19 13:42:45 -07001788static void freeCardStatus(RIL_CardStatus_v6 *p_card_status) {
Wink Savillef6aa7c12009-04-30 14:20:52 -07001789 free(p_card_status);
1790}
1791
1792/**
The Android Open Source Project00f06fc2009-03-03 19:32:15 -08001793 * SIM ready means any commands that access the SIM will work, including:
1794 * AT+CPIN, AT+CSMS, AT+CNMI, AT+CRSM
1795 * (all SMS-related commands)
1796 */
1797
1798static void pollSIMState (void *param)
1799{
1800 ATResponse *p_response;
1801 int ret;
1802
1803 if (sState != RADIO_STATE_SIM_NOT_READY) {
1804 // no longer valid to poll
1805 return;
1806 }
1807
1808 switch(getSIMStatus()) {
John Wang309ac292009-07-30 14:53:23 -07001809 case SIM_ABSENT:
1810 case SIM_PIN:
1811 case SIM_PUK:
1812 case SIM_NETWORK_PERSONALIZATION:
The Android Open Source Project00f06fc2009-03-03 19:32:15 -08001813 default:
1814 setRadioState(RADIO_STATE_SIM_LOCKED_OR_ABSENT);
1815 return;
1816
John Wang309ac292009-07-30 14:53:23 -07001817 case SIM_NOT_READY:
The Android Open Source Project00f06fc2009-03-03 19:32:15 -08001818 RIL_requestTimedCallback (pollSIMState, NULL, &TIMEVAL_SIMPOLL);
1819 return;
1820
John Wang309ac292009-07-30 14:53:23 -07001821 case SIM_READY:
The Android Open Source Project00f06fc2009-03-03 19:32:15 -08001822 setRadioState(RADIO_STATE_SIM_READY);
1823 return;
1824 }
1825}
1826
1827/** returns 1 if on, 0 if off, and -1 on error */
1828static int isRadioOn()
1829{
1830 ATResponse *p_response = NULL;
1831 int err;
1832 char *line;
1833 char ret;
1834
1835 err = at_send_command_singleline("AT+CFUN?", "+CFUN:", &p_response);
1836
1837 if (err < 0 || p_response->success == 0) {
1838 // assume radio is off
1839 goto error;
1840 }
1841
1842 line = p_response->p_intermediates->line;
1843
1844 err = at_tok_start(&line);
1845 if (err < 0) goto error;
1846
1847 err = at_tok_nextbool(&line, &ret);
1848 if (err < 0) goto error;
1849
1850 at_response_free(p_response);
1851
1852 return (int)ret;
1853
1854error:
1855
1856 at_response_free(p_response);
1857 return -1;
1858}
1859
1860/**
1861 * Initialize everything that can be configured while we're still in
1862 * AT+CFUN=0
1863 */
1864static void initializeCallback(void *param)
1865{
1866 ATResponse *p_response = NULL;
1867 int err;
1868
1869 setRadioState (RADIO_STATE_OFF);
1870
1871 at_handshake();
1872
1873 /* note: we don't check errors here. Everything important will
1874 be handled in onATTimeout and onATReaderClosed */
1875
1876 /* atchannel is tolerant of echo but it must */
1877 /* have verbose result codes */
1878 at_send_command("ATE0Q0V1", NULL);
1879
1880 /* No auto-answer */
1881 at_send_command("ATS0=0", NULL);
1882
1883 /* Extended errors */
1884 at_send_command("AT+CMEE=1", NULL);
1885
1886 /* Network registration events */
1887 err = at_send_command("AT+CREG=2", &p_response);
1888
1889 /* some handsets -- in tethered mode -- don't support CREG=2 */
1890 if (err < 0 || p_response->success == 0) {
1891 at_send_command("AT+CREG=1", NULL);
1892 }
1893
1894 at_response_free(p_response);
1895
1896 /* GPRS registration events */
1897 at_send_command("AT+CGREG=1", NULL);
1898
1899 /* Call Waiting notifications */
1900 at_send_command("AT+CCWA=1", NULL);
1901
1902 /* Alternating voice/data off */
1903 at_send_command("AT+CMOD=0", NULL);
1904
1905 /* Not muted */
1906 at_send_command("AT+CMUT=0", NULL);
1907
1908 /* +CSSU unsolicited supp service notifications */
1909 at_send_command("AT+CSSN=0,1", NULL);
1910
1911 /* no connected line identification */
1912 at_send_command("AT+COLP=0", NULL);
1913
1914 /* HEX character set */
1915 at_send_command("AT+CSCS=\"HEX\"", NULL);
1916
1917 /* USSD unsolicited */
1918 at_send_command("AT+CUSD=1", NULL);
1919
1920 /* Enable +CGEV GPRS event notifications, but don't buffer */
1921 at_send_command("AT+CGEREP=1,0", NULL);
1922
1923 /* SMS PDU mode */
1924 at_send_command("AT+CMGF=0", NULL);
1925
1926#ifdef USE_TI_COMMANDS
1927
1928 at_send_command("AT%CPI=3", NULL);
1929
1930 /* TI specific -- notifications when SMS is ready (currently ignored) */
1931 at_send_command("AT%CSTAT=1", NULL);
1932
1933#endif /* USE_TI_COMMANDS */
1934
1935
1936 /* assume radio is off on error */
1937 if (isRadioOn() > 0) {
1938 setRadioState (RADIO_STATE_SIM_NOT_READY);
1939 }
1940}
1941
1942static void waitForClose()
1943{
1944 pthread_mutex_lock(&s_state_mutex);
1945
1946 while (s_closed == 0) {
1947 pthread_cond_wait(&s_state_cond, &s_state_mutex);
1948 }
1949
1950 pthread_mutex_unlock(&s_state_mutex);
1951}
1952
1953/**
1954 * Called by atchannel when an unsolicited line appears
1955 * This is called on atchannel's reader thread. AT commands may
1956 * not be issued here
1957 */
1958static void onUnsolicited (const char *s, const char *sms_pdu)
1959{
1960 char *line = NULL;
1961 int err;
1962
1963 /* Ignore unsolicited responses until we're initialized.
1964 * This is OK because the RIL library will poll for initial state
1965 */
1966 if (sState == RADIO_STATE_UNAVAILABLE) {
1967 return;
1968 }
1969
1970 if (strStartsWith(s, "%CTZV:")) {
1971 /* TI specific -- NITZ time */
1972 char *response;
1973
1974 line = strdup(s);
1975 at_tok_start(&line);
1976
1977 err = at_tok_nextstr(&line, &response);
1978
1979 if (err != 0) {
Steve Block170fbda2012-01-08 13:48:26 +00001980 ALOGE("invalid NITZ line %s\n", s);
The Android Open Source Project00f06fc2009-03-03 19:32:15 -08001981 } else {
1982 RIL_onUnsolicitedResponse (
1983 RIL_UNSOL_NITZ_TIME_RECEIVED,
1984 response, strlen(response));
1985 }
1986 } else if (strStartsWith(s,"+CRING:")
1987 || strStartsWith(s,"RING")
1988 || strStartsWith(s,"NO CARRIER")
1989 || strStartsWith(s,"+CCWA")
1990 ) {
1991 RIL_onUnsolicitedResponse (
1992 RIL_UNSOL_RESPONSE_CALL_STATE_CHANGED,
1993 NULL, 0);
1994#ifdef WORKAROUND_FAKE_CGEV
Wink Savillef4c4d362009-04-02 01:37:03 -07001995 RIL_requestTimedCallback (onDataCallListChanged, NULL, NULL); //TODO use new function
The Android Open Source Project00f06fc2009-03-03 19:32:15 -08001996#endif /* WORKAROUND_FAKE_CGEV */
1997 } else if (strStartsWith(s,"+CREG:")
1998 || strStartsWith(s,"+CGREG:")
1999 ) {
2000 RIL_onUnsolicitedResponse (
Wink Saville2c1fb3a2011-03-19 13:42:45 -07002001 RIL_UNSOL_RESPONSE_VOICE_NETWORK_STATE_CHANGED,
The Android Open Source Project00f06fc2009-03-03 19:32:15 -08002002 NULL, 0);
2003#ifdef WORKAROUND_FAKE_CGEV
Wink Saville7f856802009-06-09 10:23:37 -07002004 RIL_requestTimedCallback (onDataCallListChanged, NULL, NULL);
The Android Open Source Project00f06fc2009-03-03 19:32:15 -08002005#endif /* WORKAROUND_FAKE_CGEV */
2006 } else if (strStartsWith(s, "+CMT:")) {
2007 RIL_onUnsolicitedResponse (
2008 RIL_UNSOL_RESPONSE_NEW_SMS,
2009 sms_pdu, strlen(sms_pdu));
2010 } else if (strStartsWith(s, "+CDS:")) {
2011 RIL_onUnsolicitedResponse (
2012 RIL_UNSOL_RESPONSE_NEW_SMS_STATUS_REPORT,
2013 sms_pdu, strlen(sms_pdu));
2014 } else if (strStartsWith(s, "+CGEV:")) {
2015 /* Really, we can ignore NW CLASS and ME CLASS events here,
2016 * but right now we don't since extranous
Wink Savillef4c4d362009-04-02 01:37:03 -07002017 * RIL_UNSOL_DATA_CALL_LIST_CHANGED calls are tolerated
The Android Open Source Project00f06fc2009-03-03 19:32:15 -08002018 */
2019 /* can't issue AT commands here -- call on main thread */
Wink Savillef4c4d362009-04-02 01:37:03 -07002020 RIL_requestTimedCallback (onDataCallListChanged, NULL, NULL);
The Android Open Source Project00f06fc2009-03-03 19:32:15 -08002021#ifdef WORKAROUND_FAKE_CGEV
2022 } else if (strStartsWith(s, "+CME ERROR: 150")) {
Wink Savillef4c4d362009-04-02 01:37:03 -07002023 RIL_requestTimedCallback (onDataCallListChanged, NULL, NULL);
The Android Open Source Project00f06fc2009-03-03 19:32:15 -08002024#endif /* WORKAROUND_FAKE_CGEV */
2025 }
2026}
2027
2028/* Called on command or reader thread */
2029static void onATReaderClosed()
2030{
Steve Blockb4e26162012-01-05 00:10:31 +00002031 ALOGI("AT channel closed\n");
The Android Open Source Project00f06fc2009-03-03 19:32:15 -08002032 at_close();
2033 s_closed = 1;
2034
2035 setRadioState (RADIO_STATE_UNAVAILABLE);
2036}
2037
2038/* Called on command thread */
2039static void onATTimeout()
2040{
Steve Blockb4e26162012-01-05 00:10:31 +00002041 ALOGI("AT channel timeout; closing\n");
The Android Open Source Project00f06fc2009-03-03 19:32:15 -08002042 at_close();
2043
2044 s_closed = 1;
2045
2046 /* FIXME cause a radio reset here */
2047
2048 setRadioState (RADIO_STATE_UNAVAILABLE);
2049}
2050
2051static void usage(char *s)
2052{
2053#ifdef RIL_SHLIB
2054 fprintf(stderr, "reference-ril requires: -p <tcp port> or -d /dev/tty_device\n");
2055#else
2056 fprintf(stderr, "usage: %s [-p <tcp port>] [-d /dev/tty_device]\n", s);
2057 exit(-1);
2058#endif
2059}
2060
2061static void *
2062mainLoop(void *param)
2063{
2064 int fd;
2065 int ret;
2066
2067 AT_DUMP("== ", "entering mainLoop()", -1 );
2068 at_set_on_reader_closed(onATReaderClosed);
2069 at_set_on_timeout(onATTimeout);
2070
2071 for (;;) {
2072 fd = -1;
2073 while (fd < 0) {
2074 if (s_port > 0) {
2075 fd = socket_loopback_client(s_port, SOCK_STREAM);
2076 } else if (s_device_socket) {
The Android Open Source Projecte6e6fb22009-03-18 17:39:47 -07002077 if (!strcmp(s_device_path, "/dev/socket/qemud")) {
Vladimir Chtchetkine385a7392011-08-04 14:03:07 -07002078 /* Before trying to connect to /dev/socket/qemud (which is
2079 * now another "legacy" way of communicating with the
2080 * emulator), we will try to connecto to gsm service via
2081 * qemu pipe. */
2082 fd = qemu_pipe_open("qemud:gsm");
2083 if (fd < 0) {
2084 /* Qemu-specific control socket */
2085 fd = socket_local_client( "qemud",
2086 ANDROID_SOCKET_NAMESPACE_RESERVED,
2087 SOCK_STREAM );
2088 if (fd >= 0 ) {
2089 char answer[2];
The Android Open Source Projecte6e6fb22009-03-18 17:39:47 -07002090
Vladimir Chtchetkine385a7392011-08-04 14:03:07 -07002091 if ( write(fd, "gsm", 3) != 3 ||
2092 read(fd, answer, 2) != 2 ||
2093 memcmp(answer, "OK", 2) != 0)
2094 {
2095 close(fd);
2096 fd = -1;
2097 }
2098 }
2099 }
The Android Open Source Projecte6e6fb22009-03-18 17:39:47 -07002100 }
2101 else
2102 fd = socket_local_client( s_device_path,
2103 ANDROID_SOCKET_NAMESPACE_FILESYSTEM,
2104 SOCK_STREAM );
The Android Open Source Project00f06fc2009-03-03 19:32:15 -08002105 } else if (s_device_path != NULL) {
2106 fd = open (s_device_path, O_RDWR);
2107 if ( fd >= 0 && !memcmp( s_device_path, "/dev/ttyS", 9 ) ) {
2108 /* disable echo on serial ports */
2109 struct termios ios;
2110 tcgetattr( fd, &ios );
2111 ios.c_lflag = 0; /* disable ECHO, ICANON, etc... */
2112 tcsetattr( fd, TCSANOW, &ios );
2113 }
2114 }
2115
2116 if (fd < 0) {
2117 perror ("opening AT interface. retrying...");
2118 sleep(10);
2119 /* never returns */
2120 }
2121 }
2122
2123 s_closed = 0;
2124 ret = at_open(fd, onUnsolicited);
2125
2126 if (ret < 0) {
Steve Block170fbda2012-01-08 13:48:26 +00002127 ALOGE ("AT error %d on at_open\n", ret);
The Android Open Source Project00f06fc2009-03-03 19:32:15 -08002128 return 0;
2129 }
2130
2131 RIL_requestTimedCallback(initializeCallback, NULL, &TIMEVAL_0);
2132
2133 // Give initializeCallback a chance to dispatched, since
2134 // we don't presently have a cancellation mechanism
2135 sleep(1);
2136
2137 waitForClose();
Steve Blockb4e26162012-01-05 00:10:31 +00002138 ALOGI("Re-opening after close");
The Android Open Source Project00f06fc2009-03-03 19:32:15 -08002139 }
2140}
2141
2142#ifdef RIL_SHLIB
2143
2144pthread_t s_tid_mainloop;
2145
2146const RIL_RadioFunctions *RIL_Init(const struct RIL_Env *env, int argc, char **argv)
2147{
2148 int ret;
2149 int fd = -1;
2150 int opt;
2151 pthread_attr_t attr;
2152
2153 s_rilenv = env;
2154
2155 while ( -1 != (opt = getopt(argc, argv, "p:d:s:"))) {
2156 switch (opt) {
2157 case 'p':
2158 s_port = atoi(optarg);
2159 if (s_port == 0) {
2160 usage(argv[0]);
2161 return NULL;
2162 }
Steve Blockb4e26162012-01-05 00:10:31 +00002163 ALOGI("Opening loopback port %d\n", s_port);
The Android Open Source Project00f06fc2009-03-03 19:32:15 -08002164 break;
2165
2166 case 'd':
2167 s_device_path = optarg;
Steve Blockb4e26162012-01-05 00:10:31 +00002168 ALOGI("Opening tty device %s\n", s_device_path);
The Android Open Source Project00f06fc2009-03-03 19:32:15 -08002169 break;
2170
2171 case 's':
2172 s_device_path = optarg;
2173 s_device_socket = 1;
Steve Blockb4e26162012-01-05 00:10:31 +00002174 ALOGI("Opening socket %s\n", s_device_path);
The Android Open Source Project00f06fc2009-03-03 19:32:15 -08002175 break;
2176
2177 default:
2178 usage(argv[0]);
2179 return NULL;
2180 }
2181 }
2182
2183 if (s_port < 0 && s_device_path == NULL) {
2184 usage(argv[0]);
2185 return NULL;
2186 }
2187
2188 pthread_attr_init (&attr);
2189 pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
2190 ret = pthread_create(&s_tid_mainloop, &attr, mainLoop, NULL);
2191
2192 return &s_callbacks;
2193}
2194#else /* RIL_SHLIB */
2195int main (int argc, char **argv)
2196{
2197 int ret;
2198 int fd = -1;
2199 int opt;
2200
2201 while ( -1 != (opt = getopt(argc, argv, "p:d:"))) {
2202 switch (opt) {
2203 case 'p':
2204 s_port = atoi(optarg);
2205 if (s_port == 0) {
2206 usage(argv[0]);
2207 }
Steve Blockb4e26162012-01-05 00:10:31 +00002208 ALOGI("Opening loopback port %d\n", s_port);
The Android Open Source Project00f06fc2009-03-03 19:32:15 -08002209 break;
2210
2211 case 'd':
2212 s_device_path = optarg;
Steve Blockb4e26162012-01-05 00:10:31 +00002213 ALOGI("Opening tty device %s\n", s_device_path);
The Android Open Source Project00f06fc2009-03-03 19:32:15 -08002214 break;
2215
2216 case 's':
2217 s_device_path = optarg;
2218 s_device_socket = 1;
Steve Blockb4e26162012-01-05 00:10:31 +00002219 ALOGI("Opening socket %s\n", s_device_path);
The Android Open Source Project00f06fc2009-03-03 19:32:15 -08002220 break;
2221
2222 default:
2223 usage(argv[0]);
2224 }
2225 }
2226
2227 if (s_port < 0 && s_device_path == NULL) {
2228 usage(argv[0]);
2229 }
2230
2231 RIL_register(&s_callbacks);
2232
2233 mainLoop(NULL);
2234
2235 return 0;
2236}
2237
2238#endif /* RIL_SHLIB */