blob: 197f0705c7f1dcd5a9cf5ea09a19f1748f5a94cb [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"
38
The Android Open Source Project00f06fc2009-03-03 19:32:15 -080039#define LOG_TAG "RIL"
40#include <utils/Log.h>
41
42#define MAX_AT_RESPONSE 0x1000
43
Wink Savillef4c4d362009-04-02 01:37:03 -070044/* pathname returned from RIL_REQUEST_SETUP_DATA_CALL / RIL_REQUEST_SETUP_DEFAULT_PDP */
Robert Greenwaltf838ede2010-07-15 18:54:53 -070045#define PPP_TTY_PATH "eth0"
The Android Open Source Project00f06fc2009-03-03 19:32:15 -080046
47#ifdef USE_TI_COMMANDS
48
49// Enable a workaround
50// 1) Make incoming call, do not answer
51// 2) Hangup remote end
52// Expected: call should disappear from CLCC line
53// Actual: Call shows as "ACTIVE" before disappearing
54#define WORKAROUND_ERRONEOUS_ANSWER 1
55
56// Some varients of the TI stack do not support the +CGEV unsolicited
57// response. However, they seem to send an unsolicited +CME ERROR: 150
58#define WORKAROUND_FAKE_CGEV 1
59#endif
60
John Wang309ac292009-07-30 14:53:23 -070061typedef enum {
62 SIM_ABSENT = 0,
63 SIM_NOT_READY = 1,
64 SIM_READY = 2, /* SIM_READY means the radio state is RADIO_STATE_SIM_READY */
65 SIM_PIN = 3,
66 SIM_PUK = 4,
67 SIM_NETWORK_PERSONALIZATION = 5
David 'Digit' Turneraf1298d2011-02-04 13:36:47 +010068} SIM_Status;
John Wang309ac292009-07-30 14:53:23 -070069
The Android Open Source Project00f06fc2009-03-03 19:32:15 -080070static void onRequest (int request, void *data, size_t datalen, RIL_Token t);
71static RIL_RadioState currentState();
72static int onSupports (int requestCode);
73static void onCancel (RIL_Token t);
74static const char *getVersion();
75static int isRadioOn();
John Wang309ac292009-07-30 14:53:23 -070076static SIM_Status getSIMStatus();
Wink Saville2c1fb3a2011-03-19 13:42:45 -070077static int getCardStatus(RIL_CardStatus_v6 **pp_card_status);
78static void freeCardStatus(RIL_CardStatus_v6 *p_card_status);
Wink Savillef4c4d362009-04-02 01:37:03 -070079static void onDataCallListChanged(void *param);
The Android Open Source Project00f06fc2009-03-03 19:32:15 -080080
81extern const char * requestToString(int request);
82
83/*** Static Variables ***/
84static const RIL_RadioFunctions s_callbacks = {
85 RIL_VERSION,
86 onRequest,
87 currentState,
88 onSupports,
89 onCancel,
90 getVersion
91};
92
93#ifdef RIL_SHLIB
94static const struct RIL_Env *s_rilenv;
95
96#define RIL_onRequestComplete(t, e, response, responselen) s_rilenv->OnRequestComplete(t,e, response, responselen)
97#define RIL_onUnsolicitedResponse(a,b,c) s_rilenv->OnUnsolicitedResponse(a,b,c)
98#define RIL_requestTimedCallback(a,b,c) s_rilenv->RequestTimedCallback(a,b,c)
99#endif
100
101static RIL_RadioState sState = RADIO_STATE_UNAVAILABLE;
102
103static pthread_mutex_t s_state_mutex = PTHREAD_MUTEX_INITIALIZER;
104static pthread_cond_t s_state_cond = PTHREAD_COND_INITIALIZER;
105
106static int s_port = -1;
107static const char * s_device_path = NULL;
108static int s_device_socket = 0;
109
110/* trigger change to this with s_state_cond */
111static int s_closed = 0;
112
113static int sFD; /* file desc of AT channel */
114static char sATBuffer[MAX_AT_RESPONSE+1];
115static char *sATBufferCur = NULL;
116
117static const struct timeval TIMEVAL_SIMPOLL = {1,0};
118static const struct timeval TIMEVAL_CALLSTATEPOLL = {0,500000};
119static const struct timeval TIMEVAL_0 = {0,0};
120
121#ifdef WORKAROUND_ERRONEOUS_ANSWER
122// Max number of times we'll try to repoll when we think
123// we have a AT+CLCC race condition
124#define REPOLL_CALLS_COUNT_MAX 4
125
126// Line index that was incoming or waiting at last poll, or -1 for none
127static int s_incomingOrWaitingLine = -1;
128// Number of times we've asked for a repoll of AT+CLCC
129static int s_repollCallsCount = 0;
130// Should we expect a call to be answered in the next CLCC?
131static int s_expectAnswer = 0;
132#endif /* WORKAROUND_ERRONEOUS_ANSWER */
133
134static void pollSIMState (void *param);
135static void setRadioState(RIL_RadioState newState);
136
137static int clccStateToRILState(int state, RIL_CallState *p_state)
138
139{
140 switch(state) {
141 case 0: *p_state = RIL_CALL_ACTIVE; return 0;
142 case 1: *p_state = RIL_CALL_HOLDING; return 0;
143 case 2: *p_state = RIL_CALL_DIALING; return 0;
144 case 3: *p_state = RIL_CALL_ALERTING; return 0;
145 case 4: *p_state = RIL_CALL_INCOMING; return 0;
146 case 5: *p_state = RIL_CALL_WAITING; return 0;
147 default: return -1;
148 }
149}
150
151/**
152 * Note: directly modified line and has *p_call point directly into
153 * modified line
154 */
Wink Saville3d54e742009-05-18 18:00:44 -0700155static int callFromCLCCLine(char *line, RIL_Call *p_call)
The Android Open Source Project00f06fc2009-03-03 19:32:15 -0800156{
157 //+CLCC: 1,0,2,0,0,\"+18005551212\",145
158 // index,isMT,state,mode,isMpty(,number,TOA)?
159
160 int err;
161 int state;
162 int mode;
163
164 err = at_tok_start(&line);
165 if (err < 0) goto error;
166
167 err = at_tok_nextint(&line, &(p_call->index));
168 if (err < 0) goto error;
169
170 err = at_tok_nextbool(&line, &(p_call->isMT));
171 if (err < 0) goto error;
172
173 err = at_tok_nextint(&line, &state);
174 if (err < 0) goto error;
175
176 err = clccStateToRILState(state, &(p_call->state));
177 if (err < 0) goto error;
178
179 err = at_tok_nextint(&line, &mode);
180 if (err < 0) goto error;
181
182 p_call->isVoice = (mode == 0);
183
184 err = at_tok_nextbool(&line, &(p_call->isMpty));
185 if (err < 0) goto error;
186
187 if (at_tok_hasmore(&line)) {
188 err = at_tok_nextstr(&line, &(p_call->number));
189
190 /* tolerate null here */
191 if (err < 0) return 0;
192
193 // Some lame implementations return strings
194 // like "NOT AVAILABLE" in the CLCC line
195 if (p_call->number != NULL
196 && 0 == strspn(p_call->number, "+0123456789")
197 ) {
198 p_call->number = NULL;
199 }
200
201 err = at_tok_nextint(&line, &p_call->toa);
202 if (err < 0) goto error;
203 }
204
Wink Saville74fa3882009-12-22 15:35:41 -0800205 p_call->uusInfo = NULL;
206
The Android Open Source Project00f06fc2009-03-03 19:32:15 -0800207 return 0;
208
209error:
210 LOGE("invalid CLCC line\n");
211 return -1;
212}
213
214
215/** do post-AT+CFUN=1 initialization */
216static void onRadioPowerOn()
217{
218#ifdef USE_TI_COMMANDS
219 /* Must be after CFUN=1 */
220 /* TI specific -- notifications for CPHS things such */
221 /* as CPHS message waiting indicator */
222
223 at_send_command("AT%CPHS=1", NULL);
224
225 /* TI specific -- enable NITZ unsol notifs */
226 at_send_command("AT%CTZV=1", NULL);
227#endif
228
229 pollSIMState(NULL);
230}
231
232/** do post- SIM ready initialization */
233static void onSIMReady()
234{
235 at_send_command_singleline("AT+CSMS=1", "+CSMS:", NULL);
236 /*
237 * Always send SMS messages directly to the TE
238 *
239 * mode = 1 // discard when link is reserved (link should never be
240 * reserved)
241 * mt = 2 // most messages routed to TE
242 * bm = 2 // new cell BM's routed to TE
243 * ds = 1 // Status reports routed to TE
244 * bfr = 1 // flush buffer
245 */
246 at_send_command("AT+CNMI=1,2,2,1,1", NULL);
247}
248
249static void requestRadioPower(void *data, size_t datalen, RIL_Token t)
250{
251 int onOff;
252
253 int err;
254 ATResponse *p_response = NULL;
255
256 assert (datalen >= sizeof(int *));
257 onOff = ((int *)data)[0];
258
259 if (onOff == 0 && sState != RADIO_STATE_OFF) {
260 err = at_send_command("AT+CFUN=0", &p_response);
261 if (err < 0 || p_response->success == 0) goto error;
262 setRadioState(RADIO_STATE_OFF);
263 } else if (onOff > 0 && sState == RADIO_STATE_OFF) {
264 err = at_send_command("AT+CFUN=1", &p_response);
265 if (err < 0|| p_response->success == 0) {
266 // Some stacks return an error when there is no SIM,
267 // but they really turn the RF portion on
268 // So, if we get an error, let's check to see if it
269 // turned on anyway
270
271 if (isRadioOn() != 1) {
272 goto error;
273 }
274 }
275 setRadioState(RADIO_STATE_SIM_NOT_READY);
276 }
277
278 at_response_free(p_response);
279 RIL_onRequestComplete(t, RIL_E_SUCCESS, NULL, 0);
280 return;
281error:
282 at_response_free(p_response);
283 RIL_onRequestComplete(t, RIL_E_GENERIC_FAILURE, NULL, 0);
284}
285
Wink Savillef4c4d362009-04-02 01:37:03 -0700286static void requestOrSendDataCallList(RIL_Token *t);
The Android Open Source Project00f06fc2009-03-03 19:32:15 -0800287
Wink Savillef4c4d362009-04-02 01:37:03 -0700288static void onDataCallListChanged(void *param)
The Android Open Source Project00f06fc2009-03-03 19:32:15 -0800289{
Wink Savillef4c4d362009-04-02 01:37:03 -0700290 requestOrSendDataCallList(NULL);
The Android Open Source Project00f06fc2009-03-03 19:32:15 -0800291}
292
Wink Savillef4c4d362009-04-02 01:37:03 -0700293static void requestDataCallList(void *data, size_t datalen, RIL_Token t)
The Android Open Source Project00f06fc2009-03-03 19:32:15 -0800294{
Wink Savillef4c4d362009-04-02 01:37:03 -0700295 requestOrSendDataCallList(&t);
The Android Open Source Project00f06fc2009-03-03 19:32:15 -0800296}
297
Wink Savillef4c4d362009-04-02 01:37:03 -0700298static void requestOrSendDataCallList(RIL_Token *t)
The Android Open Source Project00f06fc2009-03-03 19:32:15 -0800299{
300 ATResponse *p_response;
301 ATLine *p_cur;
302 int err;
303 int n = 0;
304 char *out;
305
306 err = at_send_command_multiline ("AT+CGACT?", "+CGACT:", &p_response);
307 if (err != 0 || p_response->success == 0) {
308 if (t != NULL)
309 RIL_onRequestComplete(*t, RIL_E_GENERIC_FAILURE, NULL, 0);
310 else
Wink Savillef4c4d362009-04-02 01:37:03 -0700311 RIL_onUnsolicitedResponse(RIL_UNSOL_DATA_CALL_LIST_CHANGED,
The Android Open Source Project00f06fc2009-03-03 19:32:15 -0800312 NULL, 0);
313 return;
314 }
315
316 for (p_cur = p_response->p_intermediates; p_cur != NULL;
317 p_cur = p_cur->p_next)
318 n++;
319
Wink Saville2c1fb3a2011-03-19 13:42:45 -0700320 RIL_Data_Call_Response_v6 *responses =
321 alloca(n * sizeof(RIL_Data_Call_Response_v6));
The Android Open Source Project00f06fc2009-03-03 19:32:15 -0800322
323 int i;
324 for (i = 0; i < n; i++) {
Wink Saville43808972011-01-13 17:39:51 -0800325 responses[i].status = -1;
The Android Open Source Project00f06fc2009-03-03 19:32:15 -0800326 responses[i].cid = -1;
327 responses[i].active = -1;
328 responses[i].type = "";
Wink Saville43808972011-01-13 17:39:51 -0800329 responses[i].ifname = "";
330 responses[i].addresses = "";
331 responses[i].dnses = "";
Wink Saville2c1fb3a2011-03-19 13:42:45 -0700332 responses[i].gateways = "";
The Android Open Source Project00f06fc2009-03-03 19:32:15 -0800333 }
334
Wink Saville2c1fb3a2011-03-19 13:42:45 -0700335 RIL_Data_Call_Response_v6 *response = responses;
The Android Open Source Project00f06fc2009-03-03 19:32:15 -0800336 for (p_cur = p_response->p_intermediates; p_cur != NULL;
337 p_cur = p_cur->p_next) {
338 char *line = p_cur->line;
339
340 err = at_tok_start(&line);
341 if (err < 0)
342 goto error;
343
344 err = at_tok_nextint(&line, &response->cid);
345 if (err < 0)
346 goto error;
347
348 err = at_tok_nextint(&line, &response->active);
349 if (err < 0)
350 goto error;
351
352 response++;
353 }
354
355 at_response_free(p_response);
356
357 err = at_send_command_multiline ("AT+CGDCONT?", "+CGDCONT:", &p_response);
358 if (err != 0 || p_response->success == 0) {
359 if (t != NULL)
360 RIL_onRequestComplete(*t, RIL_E_GENERIC_FAILURE, NULL, 0);
361 else
Wink Savillef4c4d362009-04-02 01:37:03 -0700362 RIL_onUnsolicitedResponse(RIL_UNSOL_DATA_CALL_LIST_CHANGED,
The Android Open Source Project00f06fc2009-03-03 19:32:15 -0800363 NULL, 0);
364 return;
365 }
366
367 for (p_cur = p_response->p_intermediates; p_cur != NULL;
368 p_cur = p_cur->p_next) {
369 char *line = p_cur->line;
370 int cid;
The Android Open Source Project00f06fc2009-03-03 19:32:15 -0800371
372 err = at_tok_start(&line);
373 if (err < 0)
374 goto error;
375
376 err = at_tok_nextint(&line, &cid);
377 if (err < 0)
378 goto error;
379
380 for (i = 0; i < n; i++) {
381 if (responses[i].cid == cid)
382 break;
383 }
384
385 if (i >= n) {
386 /* details for a context we didn't hear about in the last request */
387 continue;
388 }
389
Wink Saville43808972011-01-13 17:39:51 -0800390 // Assume no error
391 responses[i].status = 0;
392
393 // type
The Android Open Source Project00f06fc2009-03-03 19:32:15 -0800394 err = at_tok_nextstr(&line, &out);
395 if (err < 0)
396 goto error;
The Android Open Source Project00f06fc2009-03-03 19:32:15 -0800397 responses[i].type = alloca(strlen(out) + 1);
398 strcpy(responses[i].type, out);
399
Wink Saville43808972011-01-13 17:39:51 -0800400 // APN ignored for v5
The Android Open Source Project00f06fc2009-03-03 19:32:15 -0800401 err = at_tok_nextstr(&line, &out);
402 if (err < 0)
403 goto error;
404
Wink Saville43808972011-01-13 17:39:51 -0800405 responses[i].ifname = alloca(strlen(PPP_TTY_PATH) + 1);
406 strcpy(responses[i].ifname, PPP_TTY_PATH);
The Android Open Source Project00f06fc2009-03-03 19:32:15 -0800407
408 err = at_tok_nextstr(&line, &out);
409 if (err < 0)
410 goto error;
411
Wink Saville43808972011-01-13 17:39:51 -0800412 responses[i].addresses = alloca(strlen(out) + 1);
413 strcpy(responses[i].addresses, out);
414
David 'Digit' Turneraf1298d2011-02-04 13:36:47 +0100415 {
416 char propValue[PROP_VALUE_MAX];
417
418 if (__system_property_get("ro.kernel.qemu", propValue) != 0) {
419 /* We are in the emulator - the dns servers are listed
420 * by the following system properties, setup in
421 * /system/etc/init.goldfish.sh:
422 * - net.eth0.dns1
423 * - net.eth0.dns2
424 * - net.eth0.dns3
425 * - net.eth0.dns4
426 */
427 const int dnslist_sz = 128;
428 char* dnslist = alloca(dnslist_sz);
429 const char* separator = "";
430 int nn;
431
432 dnslist[0] = 0;
433 for (nn = 1; nn <= 4; nn++) {
434 /* Probe net.eth0.dns<n> */
435 char propName[PROP_NAME_MAX];
436 snprintf(propName, sizeof propName, "net.eth0.dns%d", nn);
437
438 /* Ignore if undefined */
439 if (__system_property_get(propName, propValue) == 0) {
440 continue;
441 }
442
443 /* Append the DNS IP address */
444 strlcat(dnslist, separator, dnslist_sz);
445 strlcat(dnslist, propValue, dnslist_sz);
446 separator = " ";
447 }
448 responses[i].dnses = dnslist;
Wink Saville2c1fb3a2011-03-19 13:42:45 -0700449
450 /* There is only on gateway in the emulator */
451 responses[i].gateways = "10.0.2.2";
David 'Digit' Turneraf1298d2011-02-04 13:36:47 +0100452 }
453 else {
454 /* I don't know where we are, so use the public Google DNS
Wink Saville2c1fb3a2011-03-19 13:42:45 -0700455 * servers by default and no gateway.
David 'Digit' Turneraf1298d2011-02-04 13:36:47 +0100456 */
457 responses[i].dnses = "8.8.8.8 8.8.4.4";
Wink Saville2c1fb3a2011-03-19 13:42:45 -0700458 responses[i].gateways = "";
David 'Digit' Turneraf1298d2011-02-04 13:36:47 +0100459 }
460 }
The Android Open Source Project00f06fc2009-03-03 19:32:15 -0800461 }
462
463 at_response_free(p_response);
464
465 if (t != NULL)
466 RIL_onRequestComplete(*t, RIL_E_SUCCESS, responses,
Wink Saville2c1fb3a2011-03-19 13:42:45 -0700467 n * sizeof(RIL_Data_Call_Response_v6));
The Android Open Source Project00f06fc2009-03-03 19:32:15 -0800468 else
Wink Savillef4c4d362009-04-02 01:37:03 -0700469 RIL_onUnsolicitedResponse(RIL_UNSOL_DATA_CALL_LIST_CHANGED,
The Android Open Source Project00f06fc2009-03-03 19:32:15 -0800470 responses,
Wink Saville2c1fb3a2011-03-19 13:42:45 -0700471 n * sizeof(RIL_Data_Call_Response_v6));
The Android Open Source Project00f06fc2009-03-03 19:32:15 -0800472
473 return;
474
475error:
476 if (t != NULL)
477 RIL_onRequestComplete(*t, RIL_E_GENERIC_FAILURE, NULL, 0);
478 else
Wink Savillef4c4d362009-04-02 01:37:03 -0700479 RIL_onUnsolicitedResponse(RIL_UNSOL_DATA_CALL_LIST_CHANGED,
The Android Open Source Project00f06fc2009-03-03 19:32:15 -0800480 NULL, 0);
481
482 at_response_free(p_response);
483}
484
485static void requestQueryNetworkSelectionMode(
486 void *data, size_t datalen, RIL_Token t)
487{
488 int err;
489 ATResponse *p_response = NULL;
490 int response = 0;
491 char *line;
492
493 err = at_send_command_singleline("AT+COPS?", "+COPS:", &p_response);
494
495 if (err < 0 || p_response->success == 0) {
496 goto error;
497 }
498
499 line = p_response->p_intermediates->line;
500
501 err = at_tok_start(&line);
502
503 if (err < 0) {
504 goto error;
505 }
506
507 err = at_tok_nextint(&line, &response);
508
509 if (err < 0) {
510 goto error;
511 }
512
513 RIL_onRequestComplete(t, RIL_E_SUCCESS, &response, sizeof(int));
514 at_response_free(p_response);
515 return;
516error:
517 at_response_free(p_response);
518 LOGE("requestQueryNetworkSelectionMode must never return error when radio is on");
519 RIL_onRequestComplete(t, RIL_E_GENERIC_FAILURE, NULL, 0);
520}
521
522static void sendCallStateChanged(void *param)
523{
524 RIL_onUnsolicitedResponse (
525 RIL_UNSOL_RESPONSE_CALL_STATE_CHANGED,
526 NULL, 0);
527}
528
529static void requestGetCurrentCalls(void *data, size_t datalen, RIL_Token t)
530{
531 int err;
532 ATResponse *p_response;
533 ATLine *p_cur;
534 int countCalls;
535 int countValidCalls;
Wink Saville3d54e742009-05-18 18:00:44 -0700536 RIL_Call *p_calls;
537 RIL_Call **pp_calls;
The Android Open Source Project00f06fc2009-03-03 19:32:15 -0800538 int i;
539 int needRepoll = 0;
540
541#ifdef WORKAROUND_ERRONEOUS_ANSWER
542 int prevIncomingOrWaitingLine;
543
544 prevIncomingOrWaitingLine = s_incomingOrWaitingLine;
545 s_incomingOrWaitingLine = -1;
546#endif /*WORKAROUND_ERRONEOUS_ANSWER*/
547
548 err = at_send_command_multiline ("AT+CLCC", "+CLCC:", &p_response);
549
550 if (err != 0 || p_response->success == 0) {
551 RIL_onRequestComplete(t, RIL_E_GENERIC_FAILURE, NULL, 0);
552 return;
553 }
554
555 /* count the calls */
556 for (countCalls = 0, p_cur = p_response->p_intermediates
557 ; p_cur != NULL
558 ; p_cur = p_cur->p_next
559 ) {
560 countCalls++;
561 }
562
563 /* yes, there's an array of pointers and then an array of structures */
564
Wink Saville3d54e742009-05-18 18:00:44 -0700565 pp_calls = (RIL_Call **)alloca(countCalls * sizeof(RIL_Call *));
566 p_calls = (RIL_Call *)alloca(countCalls * sizeof(RIL_Call));
567 memset (p_calls, 0, countCalls * sizeof(RIL_Call));
The Android Open Source Project00f06fc2009-03-03 19:32:15 -0800568
569 /* init the pointer array */
570 for(i = 0; i < countCalls ; i++) {
571 pp_calls[i] = &(p_calls[i]);
572 }
573
574 for (countValidCalls = 0, p_cur = p_response->p_intermediates
575 ; p_cur != NULL
576 ; p_cur = p_cur->p_next
577 ) {
578 err = callFromCLCCLine(p_cur->line, p_calls + countValidCalls);
579
580 if (err != 0) {
581 continue;
582 }
583
584#ifdef WORKAROUND_ERRONEOUS_ANSWER
585 if (p_calls[countValidCalls].state == RIL_CALL_INCOMING
586 || p_calls[countValidCalls].state == RIL_CALL_WAITING
587 ) {
588 s_incomingOrWaitingLine = p_calls[countValidCalls].index;
589 }
590#endif /*WORKAROUND_ERRONEOUS_ANSWER*/
591
592 if (p_calls[countValidCalls].state != RIL_CALL_ACTIVE
593 && p_calls[countValidCalls].state != RIL_CALL_HOLDING
594 ) {
595 needRepoll = 1;
596 }
597
598 countValidCalls++;
599 }
600
601#ifdef WORKAROUND_ERRONEOUS_ANSWER
602 // Basically:
603 // A call was incoming or waiting
604 // Now it's marked as active
605 // But we never answered it
606 //
607 // This is probably a bug, and the call will probably
608 // disappear from the call list in the next poll
609 if (prevIncomingOrWaitingLine >= 0
610 && s_incomingOrWaitingLine < 0
611 && s_expectAnswer == 0
612 ) {
613 for (i = 0; i < countValidCalls ; i++) {
614
615 if (p_calls[i].index == prevIncomingOrWaitingLine
616 && p_calls[i].state == RIL_CALL_ACTIVE
617 && s_repollCallsCount < REPOLL_CALLS_COUNT_MAX
618 ) {
619 LOGI(
620 "Hit WORKAROUND_ERRONOUS_ANSWER case."
621 " Repoll count: %d\n", s_repollCallsCount);
622 s_repollCallsCount++;
623 goto error;
624 }
625 }
626 }
627
628 s_expectAnswer = 0;
629 s_repollCallsCount = 0;
630#endif /*WORKAROUND_ERRONEOUS_ANSWER*/
631
Wink Saville3d54e742009-05-18 18:00:44 -0700632 RIL_onRequestComplete(t, RIL_E_SUCCESS, pp_calls,
633 countValidCalls * sizeof (RIL_Call *));
The Android Open Source Project00f06fc2009-03-03 19:32:15 -0800634
635 at_response_free(p_response);
636
637#ifdef POLL_CALL_STATE
638 if (countValidCalls) { // We don't seem to get a "NO CARRIER" message from
639 // smd, so we're forced to poll until the call ends.
640#else
641 if (needRepoll) {
642#endif
643 RIL_requestTimedCallback (sendCallStateChanged, NULL, &TIMEVAL_CALLSTATEPOLL);
644 }
645
646 return;
647error:
648 RIL_onRequestComplete(t, RIL_E_GENERIC_FAILURE, NULL, 0);
649 at_response_free(p_response);
650}
651
652static void requestDial(void *data, size_t datalen, RIL_Token t)
653{
654 RIL_Dial *p_dial;
655 char *cmd;
656 const char *clir;
657 int ret;
658
659 p_dial = (RIL_Dial *)data;
660
661 switch (p_dial->clir) {
662 case 1: clir = "I"; break; /*invocation*/
663 case 2: clir = "i"; break; /*suppression*/
664 default:
665 case 0: clir = ""; break; /*subscription default*/
666 }
667
668 asprintf(&cmd, "ATD%s%s;", p_dial->address, clir);
669
670 ret = at_send_command(cmd, NULL);
671
672 free(cmd);
673
674 /* success or failure is ignored by the upper layer here.
675 it will call GET_CURRENT_CALLS and determine success that way */
676 RIL_onRequestComplete(t, RIL_E_SUCCESS, NULL, 0);
677}
678
679static void requestWriteSmsToSim(void *data, size_t datalen, RIL_Token t)
680{
681 RIL_SMS_WriteArgs *p_args;
682 char *cmd;
683 int length;
684 int err;
685 ATResponse *p_response = NULL;
686
687 p_args = (RIL_SMS_WriteArgs *)data;
688
689 length = strlen(p_args->pdu)/2;
690 asprintf(&cmd, "AT+CMGW=%d,%d", length, p_args->status);
691
692 err = at_send_command_sms(cmd, p_args->pdu, "+CMGW:", &p_response);
693
694 if (err != 0 || p_response->success == 0) goto error;
695
696 RIL_onRequestComplete(t, RIL_E_SUCCESS, NULL, 0);
697 at_response_free(p_response);
698
699 return;
700error:
701 RIL_onRequestComplete(t, RIL_E_GENERIC_FAILURE, NULL, 0);
702 at_response_free(p_response);
703}
704
705static void requestHangup(void *data, size_t datalen, RIL_Token t)
706{
707 int *p_line;
708
709 int ret;
710 char *cmd;
711
712 p_line = (int *)data;
713
714 // 3GPP 22.030 6.5.5
715 // "Releases a specific active call X"
716 asprintf(&cmd, "AT+CHLD=1%d", p_line[0]);
717
718 ret = at_send_command(cmd, NULL);
719
720 free(cmd);
721
722 /* success or failure is ignored by the upper layer here.
723 it will call GET_CURRENT_CALLS and determine success that way */
724 RIL_onRequestComplete(t, RIL_E_SUCCESS, NULL, 0);
725}
726
727static void requestSignalStrength(void *data, size_t datalen, RIL_Token t)
728{
729 ATResponse *p_response = NULL;
730 int err;
731 int response[2];
732 char *line;
733
734 err = at_send_command_singleline("AT+CSQ", "+CSQ:", &p_response);
735
736 if (err < 0 || p_response->success == 0) {
737 RIL_onRequestComplete(t, RIL_E_GENERIC_FAILURE, NULL, 0);
738 goto error;
739 }
740
741 line = p_response->p_intermediates->line;
742
743 err = at_tok_start(&line);
744 if (err < 0) goto error;
745
746 err = at_tok_nextint(&line, &(response[0]));
747 if (err < 0) goto error;
748
749 err = at_tok_nextint(&line, &(response[1]));
750 if (err < 0) goto error;
751
752 RIL_onRequestComplete(t, RIL_E_SUCCESS, response, sizeof(response));
753
754 at_response_free(p_response);
755 return;
756
757error:
758 LOGE("requestSignalStrength must never return an error when radio is on");
759 RIL_onRequestComplete(t, RIL_E_GENERIC_FAILURE, NULL, 0);
760 at_response_free(p_response);
761}
762
763static void requestRegistrationState(int request, void *data,
764 size_t datalen, RIL_Token t)
765{
766 int err;
767 int response[4];
768 char * responseStr[4];
769 ATResponse *p_response = NULL;
770 const char *cmd;
771 const char *prefix;
772 char *line, *p;
773 int commas;
774 int skip;
775 int count = 3;
776
777
Wink Saville2c1fb3a2011-03-19 13:42:45 -0700778 if (request == RIL_REQUEST_VOICE_REGISTRATION_STATE) {
The Android Open Source Project00f06fc2009-03-03 19:32:15 -0800779 cmd = "AT+CREG?";
780 prefix = "+CREG:";
Wink Saville2c1fb3a2011-03-19 13:42:45 -0700781 } else if (request == RIL_REQUEST_DATA_REGISTRATION_STATE) {
The Android Open Source Project00f06fc2009-03-03 19:32:15 -0800782 cmd = "AT+CGREG?";
783 prefix = "+CGREG:";
784 } else {
785 assert(0);
786 goto error;
787 }
788
789 err = at_send_command_singleline(cmd, prefix, &p_response);
790
791 if (err != 0) goto error;
792
793 line = p_response->p_intermediates->line;
794
795 err = at_tok_start(&line);
796 if (err < 0) goto error;
797
798 /* Ok you have to be careful here
799 * The solicited version of the CREG response is
800 * +CREG: n, stat, [lac, cid]
801 * and the unsolicited version is
802 * +CREG: stat, [lac, cid]
803 * The <n> parameter is basically "is unsolicited creg on?"
804 * which it should always be
805 *
806 * Now we should normally get the solicited version here,
807 * but the unsolicited version could have snuck in
808 * so we have to handle both
809 *
810 * Also since the LAC and CID are only reported when registered,
811 * we can have 1, 2, 3, or 4 arguments here
812 *
813 * finally, a +CGREG: answer may have a fifth value that corresponds
814 * to the network type, as in;
815 *
816 * +CGREG: n, stat [,lac, cid [,networkType]]
817 */
818
819 /* count number of commas */
820 commas = 0;
821 for (p = line ; *p != '\0' ;p++) {
822 if (*p == ',') commas++;
823 }
824
825 switch (commas) {
826 case 0: /* +CREG: <stat> */
827 err = at_tok_nextint(&line, &response[0]);
828 if (err < 0) goto error;
829 response[1] = -1;
830 response[2] = -1;
831 break;
832
833 case 1: /* +CREG: <n>, <stat> */
834 err = at_tok_nextint(&line, &skip);
835 if (err < 0) goto error;
836 err = at_tok_nextint(&line, &response[0]);
837 if (err < 0) goto error;
838 response[1] = -1;
839 response[2] = -1;
840 if (err < 0) goto error;
841 break;
842
843 case 2: /* +CREG: <stat>, <lac>, <cid> */
844 err = at_tok_nextint(&line, &response[0]);
845 if (err < 0) goto error;
846 err = at_tok_nexthexint(&line, &response[1]);
847 if (err < 0) goto error;
848 err = at_tok_nexthexint(&line, &response[2]);
849 if (err < 0) goto error;
850 break;
851 case 3: /* +CREG: <n>, <stat>, <lac>, <cid> */
852 err = at_tok_nextint(&line, &skip);
853 if (err < 0) goto error;
854 err = at_tok_nextint(&line, &response[0]);
855 if (err < 0) goto error;
856 err = at_tok_nexthexint(&line, &response[1]);
857 if (err < 0) goto error;
858 err = at_tok_nexthexint(&line, &response[2]);
859 if (err < 0) goto error;
860 break;
861 /* special case for CGREG, there is a fourth parameter
862 * that is the network type (unknown/gprs/edge/umts)
863 */
864 case 4: /* +CGREG: <n>, <stat>, <lac>, <cid>, <networkType> */
865 err = at_tok_nextint(&line, &skip);
866 if (err < 0) goto error;
867 err = at_tok_nextint(&line, &response[0]);
868 if (err < 0) goto error;
869 err = at_tok_nexthexint(&line, &response[1]);
870 if (err < 0) goto error;
871 err = at_tok_nexthexint(&line, &response[2]);
872 if (err < 0) goto error;
873 err = at_tok_nexthexint(&line, &response[3]);
874 if (err < 0) goto error;
875 count = 4;
876 break;
877 default:
878 goto error;
879 }
880
881 asprintf(&responseStr[0], "%d", response[0]);
John Wang6f189a62009-06-30 13:12:53 -0700882 asprintf(&responseStr[1], "%x", response[1]);
883 asprintf(&responseStr[2], "%x", response[2]);
The Android Open Source Project00f06fc2009-03-03 19:32:15 -0800884
885 if (count > 3)
886 asprintf(&responseStr[3], "%d", response[3]);
887
888 RIL_onRequestComplete(t, RIL_E_SUCCESS, responseStr, count*sizeof(char*));
889 at_response_free(p_response);
890
891 return;
892error:
893 LOGE("requestRegistrationState must never return an error when radio is on");
894 RIL_onRequestComplete(t, RIL_E_GENERIC_FAILURE, NULL, 0);
895 at_response_free(p_response);
896}
897
898static void requestOperator(void *data, size_t datalen, RIL_Token t)
899{
900 int err;
901 int i;
902 int skip;
903 ATLine *p_cur;
904 char *response[3];
905
906 memset(response, 0, sizeof(response));
907
908 ATResponse *p_response = NULL;
909
910 err = at_send_command_multiline(
911 "AT+COPS=3,0;+COPS?;+COPS=3,1;+COPS?;+COPS=3,2;+COPS?",
912 "+COPS:", &p_response);
913
914 /* we expect 3 lines here:
915 * +COPS: 0,0,"T - Mobile"
916 * +COPS: 0,1,"TMO"
917 * +COPS: 0,2,"310170"
918 */
919
920 if (err != 0) goto error;
921
922 for (i = 0, p_cur = p_response->p_intermediates
923 ; p_cur != NULL
924 ; p_cur = p_cur->p_next, i++
925 ) {
926 char *line = p_cur->line;
927
928 err = at_tok_start(&line);
929 if (err < 0) goto error;
930
931 err = at_tok_nextint(&line, &skip);
932 if (err < 0) goto error;
933
934 // If we're unregistered, we may just get
935 // a "+COPS: 0" response
936 if (!at_tok_hasmore(&line)) {
937 response[i] = NULL;
938 continue;
939 }
940
941 err = at_tok_nextint(&line, &skip);
942 if (err < 0) goto error;
943
944 // a "+COPS: 0, n" response is also possible
945 if (!at_tok_hasmore(&line)) {
946 response[i] = NULL;
947 continue;
948 }
949
950 err = at_tok_nextstr(&line, &(response[i]));
951 if (err < 0) goto error;
952 }
953
954 if (i != 3) {
955 /* expect 3 lines exactly */
956 goto error;
957 }
958
959 RIL_onRequestComplete(t, RIL_E_SUCCESS, response, sizeof(response));
960 at_response_free(p_response);
961
962 return;
963error:
964 LOGE("requestOperator must not return error when radio is on");
965 RIL_onRequestComplete(t, RIL_E_GENERIC_FAILURE, NULL, 0);
966 at_response_free(p_response);
967}
968
969static void requestSendSMS(void *data, size_t datalen, RIL_Token t)
970{
971 int err;
972 const char *smsc;
973 const char *pdu;
974 int tpLayerLength;
975 char *cmd1, *cmd2;
976 RIL_SMS_Response response;
977 ATResponse *p_response = NULL;
978
979 smsc = ((const char **)data)[0];
980 pdu = ((const char **)data)[1];
981
982 tpLayerLength = strlen(pdu)/2;
983
984 // "NULL for default SMSC"
985 if (smsc == NULL) {
986 smsc= "00";
987 }
988
989 asprintf(&cmd1, "AT+CMGS=%d", tpLayerLength);
990 asprintf(&cmd2, "%s%s", smsc, pdu);
991
992 err = at_send_command_sms(cmd1, cmd2, "+CMGS:", &p_response);
993
994 if (err != 0 || p_response->success == 0) goto error;
995
996 memset(&response, 0, sizeof(response));
997
998 /* FIXME fill in messageRef and ackPDU */
999
1000 RIL_onRequestComplete(t, RIL_E_SUCCESS, &response, sizeof(response));
1001 at_response_free(p_response);
1002
1003 return;
1004error:
1005 RIL_onRequestComplete(t, RIL_E_GENERIC_FAILURE, NULL, 0);
1006 at_response_free(p_response);
1007}
1008
Wink Savillef4c4d362009-04-02 01:37:03 -07001009static void requestSetupDataCall(void *data, size_t datalen, RIL_Token t)
The Android Open Source Project00f06fc2009-03-03 19:32:15 -08001010{
1011 const char *apn;
1012 char *cmd;
1013 int err;
1014 ATResponse *p_response = NULL;
The Android Open Source Project00f06fc2009-03-03 19:32:15 -08001015
Wink Savillef4c4d362009-04-02 01:37:03 -07001016 apn = ((const char **)data)[2];
The Android Open Source Project00f06fc2009-03-03 19:32:15 -08001017
1018#ifdef USE_TI_COMMANDS
1019 // Config for multislot class 10 (probably default anyway eh?)
1020 err = at_send_command("AT%CPRIM=\"GMM\",\"CONFIG MULTISLOT_CLASS=<10>\"",
1021 NULL);
1022
1023 err = at_send_command("AT%DATA=2,\"UART\",1,,\"SER\",\"UART\",0", NULL);
1024#endif /* USE_TI_COMMANDS */
1025
1026 int fd, qmistatus;
1027 size_t cur = 0;
1028 size_t len;
1029 ssize_t written, rlen;
1030 char status[32] = {0};
1031 int retry = 10;
Lorenzo Colitti4f81dcf2010-09-01 19:38:57 -07001032 const char *pdp_type;
The Android Open Source Project00f06fc2009-03-03 19:32:15 -08001033
1034 LOGD("requesting data connection to APN '%s'", apn);
1035
1036 fd = open ("/dev/qmi", O_RDWR);
1037 if (fd >= 0) { /* the device doesn't exist on the emulator */
1038
Lorenzo Colitti4f81dcf2010-09-01 19:38:57 -07001039 LOGD("opened the qmi device\n");
1040 asprintf(&cmd, "up:%s", apn);
1041 len = strlen(cmd);
The Android Open Source Project00f06fc2009-03-03 19:32:15 -08001042
Lorenzo Colitti4f81dcf2010-09-01 19:38:57 -07001043 while (cur < len) {
1044 do {
1045 written = write (fd, cmd + cur, len - cur);
1046 } while (written < 0 && errno == EINTR);
The Android Open Source Project00f06fc2009-03-03 19:32:15 -08001047
Lorenzo Colitti4f81dcf2010-09-01 19:38:57 -07001048 if (written < 0) {
The Android Open Source Project00f06fc2009-03-03 19:32:15 -08001049 LOGE("### ERROR writing to /dev/qmi");
1050 close(fd);
1051 goto error;
1052 }
1053
1054 cur += written;
1055 }
1056
1057 // wait for interface to come online
1058
1059 do {
1060 sleep(1);
1061 do {
1062 rlen = read(fd, status, 31);
1063 } while (rlen < 0 && errno == EINTR);
1064
1065 if (rlen < 0) {
1066 LOGE("### ERROR reading from /dev/qmi");
1067 close(fd);
1068 goto error;
1069 } else {
1070 status[rlen] = '\0';
1071 LOGD("### status: %s", status);
1072 }
1073 } while (strncmp(status, "STATE=up", 8) && strcmp(status, "online") && --retry);
1074
1075 close(fd);
1076
1077 if (retry == 0) {
1078 LOGE("### Failed to get data connection up\n");
Lorenzo Colitti4f81dcf2010-09-01 19:38:57 -07001079 goto error;
1080 }
The Android Open Source Project00f06fc2009-03-03 19:32:15 -08001081
1082 qmistatus = system("netcfg rmnet0 dhcp");
1083
1084 LOGD("netcfg rmnet0 dhcp: status %d\n", qmistatus);
1085
Lorenzo Colitti4f81dcf2010-09-01 19:38:57 -07001086 if (qmistatus < 0) goto error;
The Android Open Source Project00f06fc2009-03-03 19:32:15 -08001087
Lorenzo Colitti4f81dcf2010-09-01 19:38:57 -07001088 } else {
The Android Open Source Project00f06fc2009-03-03 19:32:15 -08001089
Lorenzo Colitti4f81dcf2010-09-01 19:38:57 -07001090 if (datalen > 6 * sizeof(char *)) {
1091 pdp_type = ((const char **)data)[6];
1092 } else {
1093 pdp_type = "IP";
1094 }
The Android Open Source Project00f06fc2009-03-03 19:32:15 -08001095
David 'Digit' Turneraf1298d2011-02-04 13:36:47 +01001096 asprintf(&cmd, "AT+CGDCONT=1,\"%s\",\"%s\",,0,0", pdp_type, apn);
Lorenzo Colitti4f81dcf2010-09-01 19:38:57 -07001097 //FIXME check for error here
1098 err = at_send_command(cmd, NULL);
1099 free(cmd);
The Android Open Source Project00f06fc2009-03-03 19:32:15 -08001100
Lorenzo Colitti4f81dcf2010-09-01 19:38:57 -07001101 // Set required QoS params to default
1102 err = at_send_command("AT+CGQREQ=1", NULL);
The Android Open Source Project00f06fc2009-03-03 19:32:15 -08001103
Lorenzo Colitti4f81dcf2010-09-01 19:38:57 -07001104 // Set minimum QoS params to default
1105 err = at_send_command("AT+CGQMIN=1", NULL);
The Android Open Source Project00f06fc2009-03-03 19:32:15 -08001106
Lorenzo Colitti4f81dcf2010-09-01 19:38:57 -07001107 // packet-domain event reporting
1108 err = at_send_command("AT+CGEREP=1,0", NULL);
The Android Open Source Project00f06fc2009-03-03 19:32:15 -08001109
Lorenzo Colitti4f81dcf2010-09-01 19:38:57 -07001110 // Hangup anything that's happening there now
1111 err = at_send_command("AT+CGACT=1,0", NULL);
The Android Open Source Project00f06fc2009-03-03 19:32:15 -08001112
Lorenzo Colitti4f81dcf2010-09-01 19:38:57 -07001113 // Start data on PDP context 1
1114 err = at_send_command("ATD*99***1#", &p_response);
1115
1116 if (err < 0 || p_response->success == 0) {
1117 goto error;
1118 }
The Android Open Source Project00f06fc2009-03-03 19:32:15 -08001119 }
1120
Wink Saville43808972011-01-13 17:39:51 -08001121 requestOrSendDataCallList(&t);
1122
The Android Open Source Project00f06fc2009-03-03 19:32:15 -08001123 at_response_free(p_response);
1124
1125 return;
1126error:
1127 RIL_onRequestComplete(t, RIL_E_GENERIC_FAILURE, NULL, 0);
1128 at_response_free(p_response);
1129
1130}
1131
1132static void requestSMSAcknowledge(void *data, size_t datalen, RIL_Token t)
1133{
1134 int ackSuccess;
1135 int err;
1136
1137 ackSuccess = ((int *)data)[0];
1138
1139 if (ackSuccess == 1) {
1140 err = at_send_command("AT+CNMA=1", NULL);
1141 } else if (ackSuccess == 0) {
1142 err = at_send_command("AT+CNMA=2", NULL);
1143 } else {
1144 LOGE("unsupported arg to RIL_REQUEST_SMS_ACKNOWLEDGE\n");
1145 goto error;
1146 }
1147
1148 RIL_onRequestComplete(t, RIL_E_SUCCESS, NULL, 0);
1149error:
1150 RIL_onRequestComplete(t, RIL_E_GENERIC_FAILURE, NULL, 0);
1151
1152}
1153
1154static void requestSIM_IO(void *data, size_t datalen, RIL_Token t)
1155{
1156 ATResponse *p_response = NULL;
1157 RIL_SIM_IO_Response sr;
1158 int err;
1159 char *cmd = NULL;
Wink Saville2c1fb3a2011-03-19 13:42:45 -07001160 RIL_SIM_IO_v6 *p_args;
The Android Open Source Project00f06fc2009-03-03 19:32:15 -08001161 char *line;
1162
1163 memset(&sr, 0, sizeof(sr));
1164
Wink Saville2c1fb3a2011-03-19 13:42:45 -07001165 p_args = (RIL_SIM_IO_v6 *)data;
The Android Open Source Project00f06fc2009-03-03 19:32:15 -08001166
1167 /* FIXME handle pin2 */
1168
1169 if (p_args->data == NULL) {
1170 asprintf(&cmd, "AT+CRSM=%d,%d,%d,%d,%d",
1171 p_args->command, p_args->fileid,
1172 p_args->p1, p_args->p2, p_args->p3);
1173 } else {
1174 asprintf(&cmd, "AT+CRSM=%d,%d,%d,%d,%d,%s",
1175 p_args->command, p_args->fileid,
1176 p_args->p1, p_args->p2, p_args->p3, p_args->data);
1177 }
1178
1179 err = at_send_command_singleline(cmd, "+CRSM:", &p_response);
1180
1181 if (err < 0 || p_response->success == 0) {
1182 goto error;
1183 }
1184
1185 line = p_response->p_intermediates->line;
1186
1187 err = at_tok_start(&line);
1188 if (err < 0) goto error;
1189
1190 err = at_tok_nextint(&line, &(sr.sw1));
1191 if (err < 0) goto error;
1192
1193 err = at_tok_nextint(&line, &(sr.sw2));
1194 if (err < 0) goto error;
1195
1196 if (at_tok_hasmore(&line)) {
1197 err = at_tok_nextstr(&line, &(sr.simResponse));
1198 if (err < 0) goto error;
1199 }
1200
1201 RIL_onRequestComplete(t, RIL_E_SUCCESS, &sr, sizeof(sr));
1202 at_response_free(p_response);
1203 free(cmd);
1204
1205 return;
1206error:
1207 RIL_onRequestComplete(t, RIL_E_GENERIC_FAILURE, NULL, 0);
1208 at_response_free(p_response);
1209 free(cmd);
1210
1211}
1212
1213static void requestEnterSimPin(void* data, size_t datalen, RIL_Token t)
1214{
1215 ATResponse *p_response = NULL;
1216 int err;
1217 char* cmd = NULL;
1218 const char** strings = (const char**)data;;
1219
1220 if ( datalen == sizeof(char*) ) {
1221 asprintf(&cmd, "AT+CPIN=%s", strings[0]);
1222 } else if ( datalen == 2*sizeof(char*) ) {
1223 asprintf(&cmd, "AT+CPIN=%s,%s", strings[0], strings[1]);
1224 } else
1225 goto error;
1226
1227 err = at_send_command_singleline(cmd, "+CPIN:", &p_response);
1228 free(cmd);
1229
1230 if (err < 0 || p_response->success == 0) {
1231error:
1232 RIL_onRequestComplete(t, RIL_E_PASSWORD_INCORRECT, NULL, 0);
1233 } else {
1234 RIL_onRequestComplete(t, RIL_E_SUCCESS, NULL, 0);
1235 }
1236 at_response_free(p_response);
1237}
1238
1239
1240static void requestSendUSSD(void *data, size_t datalen, RIL_Token t)
1241{
1242 const char *ussdRequest;
1243
1244 ussdRequest = (char *)(data);
1245
1246
1247 RIL_onRequestComplete(t, RIL_E_REQUEST_NOT_SUPPORTED, NULL, 0);
1248
1249// @@@ TODO
1250
1251}
1252
1253
1254/*** Callback methods from the RIL library to us ***/
1255
1256/**
1257 * Call from RIL to us to make a RIL_REQUEST
1258 *
1259 * Must be completed with a call to RIL_onRequestComplete()
1260 *
1261 * RIL_onRequestComplete() may be called from any thread, before or after
1262 * this function returns.
1263 *
1264 * Will always be called from the same thread, so returning here implies
1265 * that the radio is ready to process another command (whether or not
1266 * the previous command has completed).
1267 */
1268static void
1269onRequest (int request, void *data, size_t datalen, RIL_Token t)
1270{
1271 ATResponse *p_response;
1272 int err;
1273
1274 LOGD("onRequest: %s", requestToString(request));
1275
1276 /* Ignore all requests except RIL_REQUEST_GET_SIM_STATUS
1277 * when RADIO_STATE_UNAVAILABLE.
1278 */
1279 if (sState == RADIO_STATE_UNAVAILABLE
1280 && request != RIL_REQUEST_GET_SIM_STATUS
1281 ) {
1282 RIL_onRequestComplete(t, RIL_E_RADIO_NOT_AVAILABLE, NULL, 0);
1283 return;
1284 }
1285
1286 /* Ignore all non-power requests when RADIO_STATE_OFF
1287 * (except RIL_REQUEST_GET_SIM_STATUS)
1288 */
1289 if (sState == RADIO_STATE_OFF
1290 && !(request == RIL_REQUEST_RADIO_POWER
1291 || request == RIL_REQUEST_GET_SIM_STATUS)
1292 ) {
1293 RIL_onRequestComplete(t, RIL_E_RADIO_NOT_AVAILABLE, NULL, 0);
1294 return;
1295 }
1296
1297 switch (request) {
1298 case RIL_REQUEST_GET_SIM_STATUS: {
Wink Saville2c1fb3a2011-03-19 13:42:45 -07001299 RIL_CardStatus_v6 *p_card_status;
Wink Savillef6aa7c12009-04-30 14:20:52 -07001300 char *p_buffer;
1301 int buffer_size;
The Android Open Source Project00f06fc2009-03-03 19:32:15 -08001302
Wink Savillef6aa7c12009-04-30 14:20:52 -07001303 int result = getCardStatus(&p_card_status);
1304 if (result == RIL_E_SUCCESS) {
1305 p_buffer = (char *)p_card_status;
1306 buffer_size = sizeof(*p_card_status);
1307 } else {
1308 p_buffer = NULL;
1309 buffer_size = 0;
1310 }
1311 RIL_onRequestComplete(t, result, p_buffer, buffer_size);
1312 freeCardStatus(p_card_status);
The Android Open Source Project00f06fc2009-03-03 19:32:15 -08001313 break;
1314 }
1315 case RIL_REQUEST_GET_CURRENT_CALLS:
1316 requestGetCurrentCalls(data, datalen, t);
1317 break;
1318 case RIL_REQUEST_DIAL:
1319 requestDial(data, datalen, t);
1320 break;
1321 case RIL_REQUEST_HANGUP:
1322 requestHangup(data, datalen, t);
1323 break;
1324 case RIL_REQUEST_HANGUP_WAITING_OR_BACKGROUND:
1325 // 3GPP 22.030 6.5.5
1326 // "Releases all held calls or sets User Determined User Busy
1327 // (UDUB) for a waiting call."
1328 at_send_command("AT+CHLD=0", NULL);
1329
1330 /* success or failure is ignored by the upper layer here.
1331 it will call GET_CURRENT_CALLS and determine success that way */
1332 RIL_onRequestComplete(t, RIL_E_SUCCESS, NULL, 0);
1333 break;
1334 case RIL_REQUEST_HANGUP_FOREGROUND_RESUME_BACKGROUND:
1335 // 3GPP 22.030 6.5.5
1336 // "Releases all active calls (if any exist) and accepts
1337 // the other (held or waiting) call."
1338 at_send_command("AT+CHLD=1", NULL);
1339
1340 /* success or failure is ignored by the upper layer here.
1341 it will call GET_CURRENT_CALLS and determine success that way */
1342 RIL_onRequestComplete(t, RIL_E_SUCCESS, NULL, 0);
1343 break;
1344 case RIL_REQUEST_SWITCH_WAITING_OR_HOLDING_AND_ACTIVE:
1345 // 3GPP 22.030 6.5.5
1346 // "Places all active calls (if any exist) on hold and accepts
1347 // the other (held or waiting) call."
1348 at_send_command("AT+CHLD=2", NULL);
1349
1350#ifdef WORKAROUND_ERRONEOUS_ANSWER
1351 s_expectAnswer = 1;
1352#endif /* WORKAROUND_ERRONEOUS_ANSWER */
1353
1354 /* success or failure is ignored by the upper layer here.
1355 it will call GET_CURRENT_CALLS and determine success that way */
1356 RIL_onRequestComplete(t, RIL_E_SUCCESS, NULL, 0);
1357 break;
1358 case RIL_REQUEST_ANSWER:
1359 at_send_command("ATA", NULL);
1360
1361#ifdef WORKAROUND_ERRONEOUS_ANSWER
1362 s_expectAnswer = 1;
1363#endif /* WORKAROUND_ERRONEOUS_ANSWER */
1364
1365 /* success or failure is ignored by the upper layer here.
1366 it will call GET_CURRENT_CALLS and determine success that way */
1367 RIL_onRequestComplete(t, RIL_E_SUCCESS, NULL, 0);
1368 break;
1369 case RIL_REQUEST_CONFERENCE:
1370 // 3GPP 22.030 6.5.5
1371 // "Adds a held call to the conversation"
1372 at_send_command("AT+CHLD=3", NULL);
1373
1374 /* success or failure is ignored by the upper layer here.
1375 it will call GET_CURRENT_CALLS and determine success that way */
1376 RIL_onRequestComplete(t, RIL_E_SUCCESS, NULL, 0);
1377 break;
1378 case RIL_REQUEST_UDUB:
1379 /* user determined user busy */
1380 /* sometimes used: ATH */
1381 at_send_command("ATH", NULL);
1382
1383 /* success or failure is ignored by the upper layer here.
1384 it will call GET_CURRENT_CALLS and determine success that way */
1385 RIL_onRequestComplete(t, RIL_E_SUCCESS, NULL, 0);
1386 break;
1387
1388 case RIL_REQUEST_SEPARATE_CONNECTION:
1389 {
1390 char cmd[12];
1391 int party = ((int*)data)[0];
1392
1393 // Make sure that party is in a valid range.
1394 // (Note: The Telephony middle layer imposes a range of 1 to 7.
1395 // It's sufficient for us to just make sure it's single digit.)
1396 if (party > 0 && party < 10) {
1397 sprintf(cmd, "AT+CHLD=2%d", party);
1398 at_send_command(cmd, NULL);
1399 RIL_onRequestComplete(t, RIL_E_SUCCESS, NULL, 0);
1400 } else {
1401 RIL_onRequestComplete(t, RIL_E_GENERIC_FAILURE, NULL, 0);
1402 }
1403 }
1404 break;
1405
1406 case RIL_REQUEST_SIGNAL_STRENGTH:
1407 requestSignalStrength(data, datalen, t);
1408 break;
Wink Saville2c1fb3a2011-03-19 13:42:45 -07001409 case RIL_REQUEST_VOICE_REGISTRATION_STATE:
1410 case RIL_REQUEST_DATA_REGISTRATION_STATE:
The Android Open Source Project00f06fc2009-03-03 19:32:15 -08001411 requestRegistrationState(request, data, datalen, t);
1412 break;
1413 case RIL_REQUEST_OPERATOR:
1414 requestOperator(data, datalen, t);
1415 break;
1416 case RIL_REQUEST_RADIO_POWER:
1417 requestRadioPower(data, datalen, t);
1418 break;
1419 case RIL_REQUEST_DTMF: {
1420 char c = ((char *)data)[0];
1421 char *cmd;
1422 asprintf(&cmd, "AT+VTS=%c", (int)c);
1423 at_send_command(cmd, NULL);
1424 free(cmd);
1425 RIL_onRequestComplete(t, RIL_E_SUCCESS, NULL, 0);
1426 break;
1427 }
1428 case RIL_REQUEST_SEND_SMS:
1429 requestSendSMS(data, datalen, t);
1430 break;
Wink Savillef4c4d362009-04-02 01:37:03 -07001431 case RIL_REQUEST_SETUP_DATA_CALL:
1432 requestSetupDataCall(data, datalen, t);
The Android Open Source Project00f06fc2009-03-03 19:32:15 -08001433 break;
1434 case RIL_REQUEST_SMS_ACKNOWLEDGE:
1435 requestSMSAcknowledge(data, datalen, t);
1436 break;
1437
1438 case RIL_REQUEST_GET_IMSI:
1439 p_response = NULL;
1440 err = at_send_command_numeric("AT+CIMI", &p_response);
1441
1442 if (err < 0 || p_response->success == 0) {
1443 RIL_onRequestComplete(t, RIL_E_GENERIC_FAILURE, NULL, 0);
1444 } else {
1445 RIL_onRequestComplete(t, RIL_E_SUCCESS,
1446 p_response->p_intermediates->line, sizeof(char *));
1447 }
1448 at_response_free(p_response);
1449 break;
1450
1451 case RIL_REQUEST_GET_IMEI:
1452 p_response = NULL;
1453 err = at_send_command_numeric("AT+CGSN", &p_response);
1454
1455 if (err < 0 || p_response->success == 0) {
1456 RIL_onRequestComplete(t, RIL_E_GENERIC_FAILURE, NULL, 0);
1457 } else {
1458 RIL_onRequestComplete(t, RIL_E_SUCCESS,
1459 p_response->p_intermediates->line, sizeof(char *));
1460 }
1461 at_response_free(p_response);
1462 break;
1463
1464 case RIL_REQUEST_SIM_IO:
1465 requestSIM_IO(data,datalen,t);
1466 break;
1467
1468 case RIL_REQUEST_SEND_USSD:
1469 requestSendUSSD(data, datalen, t);
1470 break;
1471
1472 case RIL_REQUEST_CANCEL_USSD:
1473 p_response = NULL;
1474 err = at_send_command_numeric("AT+CUSD=2", &p_response);
1475
1476 if (err < 0 || p_response->success == 0) {
1477 RIL_onRequestComplete(t, RIL_E_GENERIC_FAILURE, NULL, 0);
1478 } else {
1479 RIL_onRequestComplete(t, RIL_E_SUCCESS,
1480 p_response->p_intermediates->line, sizeof(char *));
1481 }
1482 at_response_free(p_response);
1483 break;
1484
1485 case RIL_REQUEST_SET_NETWORK_SELECTION_AUTOMATIC:
1486 at_send_command("AT+COPS=0", NULL);
1487 break;
1488
Wink Savillef4c4d362009-04-02 01:37:03 -07001489 case RIL_REQUEST_DATA_CALL_LIST:
1490 requestDataCallList(data, datalen, t);
The Android Open Source Project00f06fc2009-03-03 19:32:15 -08001491 break;
1492
1493 case RIL_REQUEST_QUERY_NETWORK_SELECTION_MODE:
1494 requestQueryNetworkSelectionMode(data, datalen, t);
1495 break;
1496
1497 case RIL_REQUEST_OEM_HOOK_RAW:
1498 // echo back data
1499 RIL_onRequestComplete(t, RIL_E_SUCCESS, data, datalen);
1500 break;
1501
1502
1503 case RIL_REQUEST_OEM_HOOK_STRINGS: {
1504 int i;
1505 const char ** cur;
1506
1507 LOGD("got OEM_HOOK_STRINGS: 0x%8p %lu", data, (long)datalen);
1508
1509
1510 for (i = (datalen / sizeof (char *)), cur = (const char **)data ;
1511 i > 0 ; cur++, i --) {
1512 LOGD("> '%s'", *cur);
1513 }
1514
1515 // echo back strings
1516 RIL_onRequestComplete(t, RIL_E_SUCCESS, data, datalen);
1517 break;
1518 }
1519
1520 case RIL_REQUEST_WRITE_SMS_TO_SIM:
1521 requestWriteSmsToSim(data, datalen, t);
1522 break;
1523
1524 case RIL_REQUEST_DELETE_SMS_ON_SIM: {
1525 char * cmd;
1526 p_response = NULL;
1527 asprintf(&cmd, "AT+CMGD=%d", ((int *)data)[0]);
1528 err = at_send_command(cmd, &p_response);
1529 free(cmd);
1530 if (err < 0 || p_response->success == 0) {
1531 RIL_onRequestComplete(t, RIL_E_GENERIC_FAILURE, NULL, 0);
1532 } else {
1533 RIL_onRequestComplete(t, RIL_E_SUCCESS, NULL, 0);
1534 }
1535 at_response_free(p_response);
1536 break;
1537 }
1538
1539 case RIL_REQUEST_ENTER_SIM_PIN:
1540 case RIL_REQUEST_ENTER_SIM_PUK:
1541 case RIL_REQUEST_ENTER_SIM_PIN2:
1542 case RIL_REQUEST_ENTER_SIM_PUK2:
1543 case RIL_REQUEST_CHANGE_SIM_PIN:
1544 case RIL_REQUEST_CHANGE_SIM_PIN2:
1545 requestEnterSimPin(data, datalen, t);
1546 break;
1547
1548 default:
1549 RIL_onRequestComplete(t, RIL_E_REQUEST_NOT_SUPPORTED, NULL, 0);
1550 break;
1551 }
1552}
1553
1554/**
1555 * Synchronous call from the RIL to us to return current radio state.
1556 * RADIO_STATE_UNAVAILABLE should be the initial state.
1557 */
1558static RIL_RadioState
1559currentState()
1560{
1561 return sState;
1562}
1563/**
1564 * Call from RIL to us to find out whether a specific request code
1565 * is supported by this implementation.
1566 *
1567 * Return 1 for "supported" and 0 for "unsupported"
1568 */
1569
1570static int
1571onSupports (int requestCode)
1572{
1573 //@@@ todo
1574
1575 return 1;
1576}
1577
1578static void onCancel (RIL_Token t)
1579{
1580 //@@@todo
1581
1582}
1583
1584static const char * getVersion(void)
1585{
1586 return "android reference-ril 1.0";
1587}
1588
1589static void
1590setRadioState(RIL_RadioState newState)
1591{
1592 RIL_RadioState oldState;
1593
1594 pthread_mutex_lock(&s_state_mutex);
1595
1596 oldState = sState;
1597
1598 if (s_closed > 0) {
1599 // If we're closed, the only reasonable state is
1600 // RADIO_STATE_UNAVAILABLE
1601 // This is here because things on the main thread
1602 // may attempt to change the radio state after the closed
1603 // event happened in another thread
1604 newState = RADIO_STATE_UNAVAILABLE;
1605 }
1606
1607 if (sState != newState || s_closed > 0) {
1608 sState = newState;
1609
1610 pthread_cond_broadcast (&s_state_cond);
1611 }
1612
1613 pthread_mutex_unlock(&s_state_mutex);
1614
1615
1616 /* do these outside of the mutex */
1617 if (sState != oldState) {
1618 RIL_onUnsolicitedResponse (RIL_UNSOL_RESPONSE_RADIO_STATE_CHANGED,
1619 NULL, 0);
1620
1621 /* FIXME onSimReady() and onRadioPowerOn() cannot be called
1622 * from the AT reader thread
1623 * Currently, this doesn't happen, but if that changes then these
1624 * will need to be dispatched on the request thread
1625 */
1626 if (sState == RADIO_STATE_SIM_READY) {
1627 onSIMReady();
1628 } else if (sState == RADIO_STATE_SIM_NOT_READY) {
1629 onRadioPowerOn();
1630 }
1631 }
1632}
1633
John Wang309ac292009-07-30 14:53:23 -07001634/** Returns SIM_NOT_READY on error */
David 'Digit' Turneraf1298d2011-02-04 13:36:47 +01001635static SIM_Status
The Android Open Source Project00f06fc2009-03-03 19:32:15 -08001636getSIMStatus()
1637{
1638 ATResponse *p_response = NULL;
1639 int err;
1640 int ret;
1641 char *cpinLine;
1642 char *cpinResult;
1643
1644 if (sState == RADIO_STATE_OFF || sState == RADIO_STATE_UNAVAILABLE) {
John Wang309ac292009-07-30 14:53:23 -07001645 ret = SIM_NOT_READY;
The Android Open Source Project00f06fc2009-03-03 19:32:15 -08001646 goto done;
1647 }
1648
1649 err = at_send_command_singleline("AT+CPIN?", "+CPIN:", &p_response);
1650
1651 if (err != 0) {
John Wang309ac292009-07-30 14:53:23 -07001652 ret = SIM_NOT_READY;
The Android Open Source Project00f06fc2009-03-03 19:32:15 -08001653 goto done;
1654 }
1655
1656 switch (at_get_cme_error(p_response)) {
1657 case CME_SUCCESS:
1658 break;
1659
1660 case CME_SIM_NOT_INSERTED:
John Wang309ac292009-07-30 14:53:23 -07001661 ret = SIM_ABSENT;
The Android Open Source Project00f06fc2009-03-03 19:32:15 -08001662 goto done;
1663
1664 default:
John Wang309ac292009-07-30 14:53:23 -07001665 ret = SIM_NOT_READY;
The Android Open Source Project00f06fc2009-03-03 19:32:15 -08001666 goto done;
1667 }
1668
1669 /* CPIN? has succeeded, now look at the result */
1670
1671 cpinLine = p_response->p_intermediates->line;
1672 err = at_tok_start (&cpinLine);
1673
1674 if (err < 0) {
John Wang309ac292009-07-30 14:53:23 -07001675 ret = SIM_NOT_READY;
The Android Open Source Project00f06fc2009-03-03 19:32:15 -08001676 goto done;
1677 }
1678
1679 err = at_tok_nextstr(&cpinLine, &cpinResult);
1680
1681 if (err < 0) {
John Wang309ac292009-07-30 14:53:23 -07001682 ret = SIM_NOT_READY;
The Android Open Source Project00f06fc2009-03-03 19:32:15 -08001683 goto done;
1684 }
1685
1686 if (0 == strcmp (cpinResult, "SIM PIN")) {
John Wang309ac292009-07-30 14:53:23 -07001687 ret = SIM_PIN;
The Android Open Source Project00f06fc2009-03-03 19:32:15 -08001688 goto done;
1689 } else if (0 == strcmp (cpinResult, "SIM PUK")) {
John Wang309ac292009-07-30 14:53:23 -07001690 ret = SIM_PUK;
The Android Open Source Project00f06fc2009-03-03 19:32:15 -08001691 goto done;
1692 } else if (0 == strcmp (cpinResult, "PH-NET PIN")) {
John Wang309ac292009-07-30 14:53:23 -07001693 return SIM_NETWORK_PERSONALIZATION;
The Android Open Source Project00f06fc2009-03-03 19:32:15 -08001694 } else if (0 != strcmp (cpinResult, "READY")) {
1695 /* we're treating unsupported lock types as "sim absent" */
John Wang309ac292009-07-30 14:53:23 -07001696 ret = SIM_ABSENT;
The Android Open Source Project00f06fc2009-03-03 19:32:15 -08001697 goto done;
1698 }
1699
1700 at_response_free(p_response);
1701 p_response = NULL;
1702 cpinResult = NULL;
1703
John Wang309ac292009-07-30 14:53:23 -07001704 ret = SIM_READY;
The Android Open Source Project00f06fc2009-03-03 19:32:15 -08001705
1706done:
1707 at_response_free(p_response);
1708 return ret;
1709}
1710
1711
1712/**
Wink Savillef6aa7c12009-04-30 14:20:52 -07001713 * Get the current card status.
1714 *
1715 * This must be freed using freeCardStatus.
1716 * @return: On success returns RIL_E_SUCCESS
1717 */
Wink Saville2c1fb3a2011-03-19 13:42:45 -07001718static int getCardStatus(RIL_CardStatus_v6 **pp_card_status) {
Wink Savillef6aa7c12009-04-30 14:20:52 -07001719 static RIL_AppStatus app_status_array[] = {
John Wang309ac292009-07-30 14:53:23 -07001720 // SIM_ABSENT = 0
Wink Savillef6aa7c12009-04-30 14:20:52 -07001721 { RIL_APPTYPE_UNKNOWN, RIL_APPSTATE_UNKNOWN, RIL_PERSOSUBSTATE_UNKNOWN,
1722 NULL, NULL, 0, RIL_PINSTATE_UNKNOWN, RIL_PINSTATE_UNKNOWN },
John Wang309ac292009-07-30 14:53:23 -07001723 // SIM_NOT_READY = 1
Wink Savillef6aa7c12009-04-30 14:20:52 -07001724 { RIL_APPTYPE_SIM, RIL_APPSTATE_DETECTED, RIL_PERSOSUBSTATE_UNKNOWN,
1725 NULL, NULL, 0, RIL_PINSTATE_UNKNOWN, RIL_PINSTATE_UNKNOWN },
John Wang309ac292009-07-30 14:53:23 -07001726 // SIM_READY = 2
Wink Savillef6aa7c12009-04-30 14:20:52 -07001727 { RIL_APPTYPE_SIM, RIL_APPSTATE_READY, RIL_PERSOSUBSTATE_READY,
1728 NULL, NULL, 0, RIL_PINSTATE_UNKNOWN, RIL_PINSTATE_UNKNOWN },
John Wang309ac292009-07-30 14:53:23 -07001729 // SIM_PIN = 3
Wink Savillef6aa7c12009-04-30 14:20:52 -07001730 { RIL_APPTYPE_SIM, RIL_APPSTATE_PIN, RIL_PERSOSUBSTATE_UNKNOWN,
1731 NULL, NULL, 0, RIL_PINSTATE_ENABLED_NOT_VERIFIED, RIL_PINSTATE_UNKNOWN },
John Wang309ac292009-07-30 14:53:23 -07001732 // SIM_PUK = 4
Wink Savillef6aa7c12009-04-30 14:20:52 -07001733 { RIL_APPTYPE_SIM, RIL_APPSTATE_PUK, RIL_PERSOSUBSTATE_UNKNOWN,
1734 NULL, NULL, 0, RIL_PINSTATE_ENABLED_BLOCKED, RIL_PINSTATE_UNKNOWN },
John Wang309ac292009-07-30 14:53:23 -07001735 // SIM_NETWORK_PERSONALIZATION = 5
Wink Savillef6aa7c12009-04-30 14:20:52 -07001736 { RIL_APPTYPE_SIM, RIL_APPSTATE_SUBSCRIPTION_PERSO, RIL_PERSOSUBSTATE_SIM_NETWORK,
1737 NULL, NULL, 0, RIL_PINSTATE_ENABLED_NOT_VERIFIED, RIL_PINSTATE_UNKNOWN }
1738 };
1739 RIL_CardState card_state;
1740 int num_apps;
1741
1742 int sim_status = getSIMStatus();
John Wang309ac292009-07-30 14:53:23 -07001743 if (sim_status == SIM_ABSENT) {
Wink Savillef6aa7c12009-04-30 14:20:52 -07001744 card_state = RIL_CARDSTATE_ABSENT;
1745 num_apps = 0;
1746 } else {
1747 card_state = RIL_CARDSTATE_PRESENT;
1748 num_apps = 1;
1749 }
1750
1751 // Allocate and initialize base card status.
Wink Saville2c1fb3a2011-03-19 13:42:45 -07001752 RIL_CardStatus_v6 *p_card_status = malloc(sizeof(RIL_CardStatus_v6));
Wink Savillef6aa7c12009-04-30 14:20:52 -07001753 p_card_status->card_state = card_state;
1754 p_card_status->universal_pin_state = RIL_PINSTATE_UNKNOWN;
1755 p_card_status->gsm_umts_subscription_app_index = RIL_CARD_MAX_APPS;
1756 p_card_status->cdma_subscription_app_index = RIL_CARD_MAX_APPS;
Wink Saville2c1fb3a2011-03-19 13:42:45 -07001757 p_card_status->ims_subscription_app_index = RIL_CARD_MAX_APPS;
Wink Savillef6aa7c12009-04-30 14:20:52 -07001758 p_card_status->num_applications = num_apps;
1759
1760 // Initialize application status
1761 int i;
1762 for (i = 0; i < RIL_CARD_MAX_APPS; i++) {
John Wang309ac292009-07-30 14:53:23 -07001763 p_card_status->applications[i] = app_status_array[SIM_ABSENT];
Wink Savillef6aa7c12009-04-30 14:20:52 -07001764 }
1765
1766 // Pickup the appropriate application status
1767 // that reflects sim_status for gsm.
1768 if (num_apps != 0) {
1769 // Only support one app, gsm
1770 p_card_status->num_applications = 1;
1771 p_card_status->gsm_umts_subscription_app_index = 0;
1772
1773 // Get the correct app status
1774 p_card_status->applications[0] = app_status_array[sim_status];
1775 }
1776
1777 *pp_card_status = p_card_status;
1778 return RIL_E_SUCCESS;
1779}
1780
1781/**
1782 * Free the card status returned by getCardStatus
1783 */
Wink Saville2c1fb3a2011-03-19 13:42:45 -07001784static void freeCardStatus(RIL_CardStatus_v6 *p_card_status) {
Wink Savillef6aa7c12009-04-30 14:20:52 -07001785 free(p_card_status);
1786}
1787
1788/**
The Android Open Source Project00f06fc2009-03-03 19:32:15 -08001789 * SIM ready means any commands that access the SIM will work, including:
1790 * AT+CPIN, AT+CSMS, AT+CNMI, AT+CRSM
1791 * (all SMS-related commands)
1792 */
1793
1794static void pollSIMState (void *param)
1795{
1796 ATResponse *p_response;
1797 int ret;
1798
1799 if (sState != RADIO_STATE_SIM_NOT_READY) {
1800 // no longer valid to poll
1801 return;
1802 }
1803
1804 switch(getSIMStatus()) {
John Wang309ac292009-07-30 14:53:23 -07001805 case SIM_ABSENT:
1806 case SIM_PIN:
1807 case SIM_PUK:
1808 case SIM_NETWORK_PERSONALIZATION:
The Android Open Source Project00f06fc2009-03-03 19:32:15 -08001809 default:
1810 setRadioState(RADIO_STATE_SIM_LOCKED_OR_ABSENT);
1811 return;
1812
John Wang309ac292009-07-30 14:53:23 -07001813 case SIM_NOT_READY:
The Android Open Source Project00f06fc2009-03-03 19:32:15 -08001814 RIL_requestTimedCallback (pollSIMState, NULL, &TIMEVAL_SIMPOLL);
1815 return;
1816
John Wang309ac292009-07-30 14:53:23 -07001817 case SIM_READY:
The Android Open Source Project00f06fc2009-03-03 19:32:15 -08001818 setRadioState(RADIO_STATE_SIM_READY);
1819 return;
1820 }
1821}
1822
1823/** returns 1 if on, 0 if off, and -1 on error */
1824static int isRadioOn()
1825{
1826 ATResponse *p_response = NULL;
1827 int err;
1828 char *line;
1829 char ret;
1830
1831 err = at_send_command_singleline("AT+CFUN?", "+CFUN:", &p_response);
1832
1833 if (err < 0 || p_response->success == 0) {
1834 // assume radio is off
1835 goto error;
1836 }
1837
1838 line = p_response->p_intermediates->line;
1839
1840 err = at_tok_start(&line);
1841 if (err < 0) goto error;
1842
1843 err = at_tok_nextbool(&line, &ret);
1844 if (err < 0) goto error;
1845
1846 at_response_free(p_response);
1847
1848 return (int)ret;
1849
1850error:
1851
1852 at_response_free(p_response);
1853 return -1;
1854}
1855
1856/**
1857 * Initialize everything that can be configured while we're still in
1858 * AT+CFUN=0
1859 */
1860static void initializeCallback(void *param)
1861{
1862 ATResponse *p_response = NULL;
1863 int err;
1864
1865 setRadioState (RADIO_STATE_OFF);
1866
1867 at_handshake();
1868
1869 /* note: we don't check errors here. Everything important will
1870 be handled in onATTimeout and onATReaderClosed */
1871
1872 /* atchannel is tolerant of echo but it must */
1873 /* have verbose result codes */
1874 at_send_command("ATE0Q0V1", NULL);
1875
1876 /* No auto-answer */
1877 at_send_command("ATS0=0", NULL);
1878
1879 /* Extended errors */
1880 at_send_command("AT+CMEE=1", NULL);
1881
1882 /* Network registration events */
1883 err = at_send_command("AT+CREG=2", &p_response);
1884
1885 /* some handsets -- in tethered mode -- don't support CREG=2 */
1886 if (err < 0 || p_response->success == 0) {
1887 at_send_command("AT+CREG=1", NULL);
1888 }
1889
1890 at_response_free(p_response);
1891
1892 /* GPRS registration events */
1893 at_send_command("AT+CGREG=1", NULL);
1894
1895 /* Call Waiting notifications */
1896 at_send_command("AT+CCWA=1", NULL);
1897
1898 /* Alternating voice/data off */
1899 at_send_command("AT+CMOD=0", NULL);
1900
1901 /* Not muted */
1902 at_send_command("AT+CMUT=0", NULL);
1903
1904 /* +CSSU unsolicited supp service notifications */
1905 at_send_command("AT+CSSN=0,1", NULL);
1906
1907 /* no connected line identification */
1908 at_send_command("AT+COLP=0", NULL);
1909
1910 /* HEX character set */
1911 at_send_command("AT+CSCS=\"HEX\"", NULL);
1912
1913 /* USSD unsolicited */
1914 at_send_command("AT+CUSD=1", NULL);
1915
1916 /* Enable +CGEV GPRS event notifications, but don't buffer */
1917 at_send_command("AT+CGEREP=1,0", NULL);
1918
1919 /* SMS PDU mode */
1920 at_send_command("AT+CMGF=0", NULL);
1921
1922#ifdef USE_TI_COMMANDS
1923
1924 at_send_command("AT%CPI=3", NULL);
1925
1926 /* TI specific -- notifications when SMS is ready (currently ignored) */
1927 at_send_command("AT%CSTAT=1", NULL);
1928
1929#endif /* USE_TI_COMMANDS */
1930
1931
1932 /* assume radio is off on error */
1933 if (isRadioOn() > 0) {
1934 setRadioState (RADIO_STATE_SIM_NOT_READY);
1935 }
1936}
1937
1938static void waitForClose()
1939{
1940 pthread_mutex_lock(&s_state_mutex);
1941
1942 while (s_closed == 0) {
1943 pthread_cond_wait(&s_state_cond, &s_state_mutex);
1944 }
1945
1946 pthread_mutex_unlock(&s_state_mutex);
1947}
1948
1949/**
1950 * Called by atchannel when an unsolicited line appears
1951 * This is called on atchannel's reader thread. AT commands may
1952 * not be issued here
1953 */
1954static void onUnsolicited (const char *s, const char *sms_pdu)
1955{
1956 char *line = NULL;
1957 int err;
1958
1959 /* Ignore unsolicited responses until we're initialized.
1960 * This is OK because the RIL library will poll for initial state
1961 */
1962 if (sState == RADIO_STATE_UNAVAILABLE) {
1963 return;
1964 }
1965
1966 if (strStartsWith(s, "%CTZV:")) {
1967 /* TI specific -- NITZ time */
1968 char *response;
1969
1970 line = strdup(s);
1971 at_tok_start(&line);
1972
1973 err = at_tok_nextstr(&line, &response);
1974
1975 if (err != 0) {
1976 LOGE("invalid NITZ line %s\n", s);
1977 } else {
1978 RIL_onUnsolicitedResponse (
1979 RIL_UNSOL_NITZ_TIME_RECEIVED,
1980 response, strlen(response));
1981 }
1982 } else if (strStartsWith(s,"+CRING:")
1983 || strStartsWith(s,"RING")
1984 || strStartsWith(s,"NO CARRIER")
1985 || strStartsWith(s,"+CCWA")
1986 ) {
1987 RIL_onUnsolicitedResponse (
1988 RIL_UNSOL_RESPONSE_CALL_STATE_CHANGED,
1989 NULL, 0);
1990#ifdef WORKAROUND_FAKE_CGEV
Wink Savillef4c4d362009-04-02 01:37:03 -07001991 RIL_requestTimedCallback (onDataCallListChanged, NULL, NULL); //TODO use new function
The Android Open Source Project00f06fc2009-03-03 19:32:15 -08001992#endif /* WORKAROUND_FAKE_CGEV */
1993 } else if (strStartsWith(s,"+CREG:")
1994 || strStartsWith(s,"+CGREG:")
1995 ) {
1996 RIL_onUnsolicitedResponse (
Wink Saville2c1fb3a2011-03-19 13:42:45 -07001997 RIL_UNSOL_RESPONSE_VOICE_NETWORK_STATE_CHANGED,
The Android Open Source Project00f06fc2009-03-03 19:32:15 -08001998 NULL, 0);
1999#ifdef WORKAROUND_FAKE_CGEV
Wink Saville7f856802009-06-09 10:23:37 -07002000 RIL_requestTimedCallback (onDataCallListChanged, NULL, NULL);
The Android Open Source Project00f06fc2009-03-03 19:32:15 -08002001#endif /* WORKAROUND_FAKE_CGEV */
2002 } else if (strStartsWith(s, "+CMT:")) {
2003 RIL_onUnsolicitedResponse (
2004 RIL_UNSOL_RESPONSE_NEW_SMS,
2005 sms_pdu, strlen(sms_pdu));
2006 } else if (strStartsWith(s, "+CDS:")) {
2007 RIL_onUnsolicitedResponse (
2008 RIL_UNSOL_RESPONSE_NEW_SMS_STATUS_REPORT,
2009 sms_pdu, strlen(sms_pdu));
2010 } else if (strStartsWith(s, "+CGEV:")) {
2011 /* Really, we can ignore NW CLASS and ME CLASS events here,
2012 * but right now we don't since extranous
Wink Savillef4c4d362009-04-02 01:37:03 -07002013 * RIL_UNSOL_DATA_CALL_LIST_CHANGED calls are tolerated
The Android Open Source Project00f06fc2009-03-03 19:32:15 -08002014 */
2015 /* can't issue AT commands here -- call on main thread */
Wink Savillef4c4d362009-04-02 01:37:03 -07002016 RIL_requestTimedCallback (onDataCallListChanged, NULL, NULL);
The Android Open Source Project00f06fc2009-03-03 19:32:15 -08002017#ifdef WORKAROUND_FAKE_CGEV
2018 } else if (strStartsWith(s, "+CME ERROR: 150")) {
Wink Savillef4c4d362009-04-02 01:37:03 -07002019 RIL_requestTimedCallback (onDataCallListChanged, NULL, NULL);
The Android Open Source Project00f06fc2009-03-03 19:32:15 -08002020#endif /* WORKAROUND_FAKE_CGEV */
2021 }
2022}
2023
2024/* Called on command or reader thread */
2025static void onATReaderClosed()
2026{
2027 LOGI("AT channel closed\n");
2028 at_close();
2029 s_closed = 1;
2030
2031 setRadioState (RADIO_STATE_UNAVAILABLE);
2032}
2033
2034/* Called on command thread */
2035static void onATTimeout()
2036{
2037 LOGI("AT channel timeout; closing\n");
2038 at_close();
2039
2040 s_closed = 1;
2041
2042 /* FIXME cause a radio reset here */
2043
2044 setRadioState (RADIO_STATE_UNAVAILABLE);
2045}
2046
2047static void usage(char *s)
2048{
2049#ifdef RIL_SHLIB
2050 fprintf(stderr, "reference-ril requires: -p <tcp port> or -d /dev/tty_device\n");
2051#else
2052 fprintf(stderr, "usage: %s [-p <tcp port>] [-d /dev/tty_device]\n", s);
2053 exit(-1);
2054#endif
2055}
2056
2057static void *
2058mainLoop(void *param)
2059{
2060 int fd;
2061 int ret;
2062
2063 AT_DUMP("== ", "entering mainLoop()", -1 );
2064 at_set_on_reader_closed(onATReaderClosed);
2065 at_set_on_timeout(onATTimeout);
2066
2067 for (;;) {
2068 fd = -1;
2069 while (fd < 0) {
2070 if (s_port > 0) {
2071 fd = socket_loopback_client(s_port, SOCK_STREAM);
2072 } else if (s_device_socket) {
The Android Open Source Projecte6e6fb22009-03-18 17:39:47 -07002073 if (!strcmp(s_device_path, "/dev/socket/qemud")) {
2074 /* Qemu-specific control socket */
2075 fd = socket_local_client( "qemud",
2076 ANDROID_SOCKET_NAMESPACE_RESERVED,
2077 SOCK_STREAM );
2078 if (fd >= 0 ) {
2079 char answer[2];
2080
2081 if ( write(fd, "gsm", 3) != 3 ||
2082 read(fd, answer, 2) != 2 ||
2083 memcmp(answer, "OK", 2) != 0)
2084 {
2085 close(fd);
2086 fd = -1;
2087 }
2088 }
2089 }
2090 else
2091 fd = socket_local_client( s_device_path,
2092 ANDROID_SOCKET_NAMESPACE_FILESYSTEM,
2093 SOCK_STREAM );
The Android Open Source Project00f06fc2009-03-03 19:32:15 -08002094 } else if (s_device_path != NULL) {
2095 fd = open (s_device_path, O_RDWR);
2096 if ( fd >= 0 && !memcmp( s_device_path, "/dev/ttyS", 9 ) ) {
2097 /* disable echo on serial ports */
2098 struct termios ios;
2099 tcgetattr( fd, &ios );
2100 ios.c_lflag = 0; /* disable ECHO, ICANON, etc... */
2101 tcsetattr( fd, TCSANOW, &ios );
2102 }
2103 }
2104
2105 if (fd < 0) {
2106 perror ("opening AT interface. retrying...");
2107 sleep(10);
2108 /* never returns */
2109 }
2110 }
2111
2112 s_closed = 0;
2113 ret = at_open(fd, onUnsolicited);
2114
2115 if (ret < 0) {
2116 LOGE ("AT error %d on at_open\n", ret);
2117 return 0;
2118 }
2119
2120 RIL_requestTimedCallback(initializeCallback, NULL, &TIMEVAL_0);
2121
2122 // Give initializeCallback a chance to dispatched, since
2123 // we don't presently have a cancellation mechanism
2124 sleep(1);
2125
2126 waitForClose();
2127 LOGI("Re-opening after close");
2128 }
2129}
2130
2131#ifdef RIL_SHLIB
2132
2133pthread_t s_tid_mainloop;
2134
2135const RIL_RadioFunctions *RIL_Init(const struct RIL_Env *env, int argc, char **argv)
2136{
2137 int ret;
2138 int fd = -1;
2139 int opt;
2140 pthread_attr_t attr;
2141
2142 s_rilenv = env;
2143
2144 while ( -1 != (opt = getopt(argc, argv, "p:d:s:"))) {
2145 switch (opt) {
2146 case 'p':
2147 s_port = atoi(optarg);
2148 if (s_port == 0) {
2149 usage(argv[0]);
2150 return NULL;
2151 }
2152 LOGI("Opening loopback port %d\n", s_port);
2153 break;
2154
2155 case 'd':
2156 s_device_path = optarg;
2157 LOGI("Opening tty device %s\n", s_device_path);
2158 break;
2159
2160 case 's':
2161 s_device_path = optarg;
2162 s_device_socket = 1;
2163 LOGI("Opening socket %s\n", s_device_path);
2164 break;
2165
2166 default:
2167 usage(argv[0]);
2168 return NULL;
2169 }
2170 }
2171
2172 if (s_port < 0 && s_device_path == NULL) {
2173 usage(argv[0]);
2174 return NULL;
2175 }
2176
2177 pthread_attr_init (&attr);
2178 pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
2179 ret = pthread_create(&s_tid_mainloop, &attr, mainLoop, NULL);
2180
2181 return &s_callbacks;
2182}
2183#else /* RIL_SHLIB */
2184int main (int argc, char **argv)
2185{
2186 int ret;
2187 int fd = -1;
2188 int opt;
2189
2190 while ( -1 != (opt = getopt(argc, argv, "p:d:"))) {
2191 switch (opt) {
2192 case 'p':
2193 s_port = atoi(optarg);
2194 if (s_port == 0) {
2195 usage(argv[0]);
2196 }
2197 LOGI("Opening loopback port %d\n", s_port);
2198 break;
2199
2200 case 'd':
2201 s_device_path = optarg;
2202 LOGI("Opening tty device %s\n", s_device_path);
2203 break;
2204
2205 case 's':
2206 s_device_path = optarg;
2207 s_device_socket = 1;
2208 LOGI("Opening socket %s\n", s_device_path);
2209 break;
2210
2211 default:
2212 usage(argv[0]);
2213 }
2214 }
2215
2216 if (s_port < 0 && s_device_path == NULL) {
2217 usage(argv[0]);
2218 }
2219
2220 RIL_register(&s_callbacks);
2221
2222 mainLoop(NULL);
2223
2224 return 0;
2225}
2226
2227#endif /* RIL_SHLIB */