blob: 02a7e12200141a40bff957828d30304df97e7ddc [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;
Wink Saville250eb3c2011-06-22 09:11:34 -0700326 responses[i].suggestedRetryTime = -1;
The Android Open Source Project00f06fc2009-03-03 19:32:15 -0800327 responses[i].cid = -1;
328 responses[i].active = -1;
329 responses[i].type = "";
Wink Saville43808972011-01-13 17:39:51 -0800330 responses[i].ifname = "";
331 responses[i].addresses = "";
332 responses[i].dnses = "";
Wink Saville2c1fb3a2011-03-19 13:42:45 -0700333 responses[i].gateways = "";
The Android Open Source Project00f06fc2009-03-03 19:32:15 -0800334 }
335
Wink Saville2c1fb3a2011-03-19 13:42:45 -0700336 RIL_Data_Call_Response_v6 *response = responses;
The Android Open Source Project00f06fc2009-03-03 19:32:15 -0800337 for (p_cur = p_response->p_intermediates; p_cur != NULL;
338 p_cur = p_cur->p_next) {
339 char *line = p_cur->line;
340
341 err = at_tok_start(&line);
342 if (err < 0)
343 goto error;
344
345 err = at_tok_nextint(&line, &response->cid);
346 if (err < 0)
347 goto error;
348
349 err = at_tok_nextint(&line, &response->active);
350 if (err < 0)
351 goto error;
352
353 response++;
354 }
355
356 at_response_free(p_response);
357
358 err = at_send_command_multiline ("AT+CGDCONT?", "+CGDCONT:", &p_response);
359 if (err != 0 || p_response->success == 0) {
360 if (t != NULL)
361 RIL_onRequestComplete(*t, RIL_E_GENERIC_FAILURE, NULL, 0);
362 else
Wink Savillef4c4d362009-04-02 01:37:03 -0700363 RIL_onUnsolicitedResponse(RIL_UNSOL_DATA_CALL_LIST_CHANGED,
The Android Open Source Project00f06fc2009-03-03 19:32:15 -0800364 NULL, 0);
365 return;
366 }
367
368 for (p_cur = p_response->p_intermediates; p_cur != NULL;
369 p_cur = p_cur->p_next) {
370 char *line = p_cur->line;
371 int cid;
The Android Open Source Project00f06fc2009-03-03 19:32:15 -0800372
373 err = at_tok_start(&line);
374 if (err < 0)
375 goto error;
376
377 err = at_tok_nextint(&line, &cid);
378 if (err < 0)
379 goto error;
380
381 for (i = 0; i < n; i++) {
382 if (responses[i].cid == cid)
383 break;
384 }
385
386 if (i >= n) {
387 /* details for a context we didn't hear about in the last request */
388 continue;
389 }
390
Wink Saville43808972011-01-13 17:39:51 -0800391 // Assume no error
392 responses[i].status = 0;
393
394 // type
The Android Open Source Project00f06fc2009-03-03 19:32:15 -0800395 err = at_tok_nextstr(&line, &out);
396 if (err < 0)
397 goto error;
The Android Open Source Project00f06fc2009-03-03 19:32:15 -0800398 responses[i].type = alloca(strlen(out) + 1);
399 strcpy(responses[i].type, out);
400
Wink Saville43808972011-01-13 17:39:51 -0800401 // APN ignored for v5
The Android Open Source Project00f06fc2009-03-03 19:32:15 -0800402 err = at_tok_nextstr(&line, &out);
403 if (err < 0)
404 goto error;
405
Wink Saville43808972011-01-13 17:39:51 -0800406 responses[i].ifname = alloca(strlen(PPP_TTY_PATH) + 1);
407 strcpy(responses[i].ifname, PPP_TTY_PATH);
The Android Open Source Project00f06fc2009-03-03 19:32:15 -0800408
409 err = at_tok_nextstr(&line, &out);
410 if (err < 0)
411 goto error;
412
Wink Saville43808972011-01-13 17:39:51 -0800413 responses[i].addresses = alloca(strlen(out) + 1);
414 strcpy(responses[i].addresses, out);
415
David 'Digit' Turneraf1298d2011-02-04 13:36:47 +0100416 {
417 char propValue[PROP_VALUE_MAX];
418
419 if (__system_property_get("ro.kernel.qemu", propValue) != 0) {
420 /* We are in the emulator - the dns servers are listed
421 * by the following system properties, setup in
422 * /system/etc/init.goldfish.sh:
423 * - net.eth0.dns1
424 * - net.eth0.dns2
425 * - net.eth0.dns3
426 * - net.eth0.dns4
427 */
428 const int dnslist_sz = 128;
429 char* dnslist = alloca(dnslist_sz);
430 const char* separator = "";
431 int nn;
432
433 dnslist[0] = 0;
434 for (nn = 1; nn <= 4; nn++) {
435 /* Probe net.eth0.dns<n> */
436 char propName[PROP_NAME_MAX];
437 snprintf(propName, sizeof propName, "net.eth0.dns%d", nn);
438
439 /* Ignore if undefined */
440 if (__system_property_get(propName, propValue) == 0) {
441 continue;
442 }
443
444 /* Append the DNS IP address */
445 strlcat(dnslist, separator, dnslist_sz);
446 strlcat(dnslist, propValue, dnslist_sz);
447 separator = " ";
448 }
449 responses[i].dnses = dnslist;
Wink Saville2c1fb3a2011-03-19 13:42:45 -0700450
451 /* There is only on gateway in the emulator */
452 responses[i].gateways = "10.0.2.2";
David 'Digit' Turneraf1298d2011-02-04 13:36:47 +0100453 }
454 else {
455 /* I don't know where we are, so use the public Google DNS
Wink Saville2c1fb3a2011-03-19 13:42:45 -0700456 * servers by default and no gateway.
David 'Digit' Turneraf1298d2011-02-04 13:36:47 +0100457 */
458 responses[i].dnses = "8.8.8.8 8.8.4.4";
Wink Saville2c1fb3a2011-03-19 13:42:45 -0700459 responses[i].gateways = "";
David 'Digit' Turneraf1298d2011-02-04 13:36:47 +0100460 }
461 }
The Android Open Source Project00f06fc2009-03-03 19:32:15 -0800462 }
463
464 at_response_free(p_response);
465
466 if (t != NULL)
467 RIL_onRequestComplete(*t, RIL_E_SUCCESS, responses,
Wink Saville2c1fb3a2011-03-19 13:42:45 -0700468 n * sizeof(RIL_Data_Call_Response_v6));
The Android Open Source Project00f06fc2009-03-03 19:32:15 -0800469 else
Wink Savillef4c4d362009-04-02 01:37:03 -0700470 RIL_onUnsolicitedResponse(RIL_UNSOL_DATA_CALL_LIST_CHANGED,
The Android Open Source Project00f06fc2009-03-03 19:32:15 -0800471 responses,
Wink Saville2c1fb3a2011-03-19 13:42:45 -0700472 n * sizeof(RIL_Data_Call_Response_v6));
The Android Open Source Project00f06fc2009-03-03 19:32:15 -0800473
474 return;
475
476error:
477 if (t != NULL)
478 RIL_onRequestComplete(*t, RIL_E_GENERIC_FAILURE, NULL, 0);
479 else
Wink Savillef4c4d362009-04-02 01:37:03 -0700480 RIL_onUnsolicitedResponse(RIL_UNSOL_DATA_CALL_LIST_CHANGED,
The Android Open Source Project00f06fc2009-03-03 19:32:15 -0800481 NULL, 0);
482
483 at_response_free(p_response);
484}
485
486static void requestQueryNetworkSelectionMode(
487 void *data, size_t datalen, RIL_Token t)
488{
489 int err;
490 ATResponse *p_response = NULL;
491 int response = 0;
492 char *line;
493
494 err = at_send_command_singleline("AT+COPS?", "+COPS:", &p_response);
495
496 if (err < 0 || p_response->success == 0) {
497 goto error;
498 }
499
500 line = p_response->p_intermediates->line;
501
502 err = at_tok_start(&line);
503
504 if (err < 0) {
505 goto error;
506 }
507
508 err = at_tok_nextint(&line, &response);
509
510 if (err < 0) {
511 goto error;
512 }
513
514 RIL_onRequestComplete(t, RIL_E_SUCCESS, &response, sizeof(int));
515 at_response_free(p_response);
516 return;
517error:
518 at_response_free(p_response);
519 LOGE("requestQueryNetworkSelectionMode must never return error when radio is on");
520 RIL_onRequestComplete(t, RIL_E_GENERIC_FAILURE, NULL, 0);
521}
522
523static void sendCallStateChanged(void *param)
524{
525 RIL_onUnsolicitedResponse (
526 RIL_UNSOL_RESPONSE_CALL_STATE_CHANGED,
527 NULL, 0);
528}
529
530static void requestGetCurrentCalls(void *data, size_t datalen, RIL_Token t)
531{
532 int err;
533 ATResponse *p_response;
534 ATLine *p_cur;
535 int countCalls;
536 int countValidCalls;
Wink Saville3d54e742009-05-18 18:00:44 -0700537 RIL_Call *p_calls;
538 RIL_Call **pp_calls;
The Android Open Source Project00f06fc2009-03-03 19:32:15 -0800539 int i;
540 int needRepoll = 0;
541
542#ifdef WORKAROUND_ERRONEOUS_ANSWER
543 int prevIncomingOrWaitingLine;
544
545 prevIncomingOrWaitingLine = s_incomingOrWaitingLine;
546 s_incomingOrWaitingLine = -1;
547#endif /*WORKAROUND_ERRONEOUS_ANSWER*/
548
549 err = at_send_command_multiline ("AT+CLCC", "+CLCC:", &p_response);
550
551 if (err != 0 || p_response->success == 0) {
552 RIL_onRequestComplete(t, RIL_E_GENERIC_FAILURE, NULL, 0);
553 return;
554 }
555
556 /* count the calls */
557 for (countCalls = 0, p_cur = p_response->p_intermediates
558 ; p_cur != NULL
559 ; p_cur = p_cur->p_next
560 ) {
561 countCalls++;
562 }
563
564 /* yes, there's an array of pointers and then an array of structures */
565
Wink Saville3d54e742009-05-18 18:00:44 -0700566 pp_calls = (RIL_Call **)alloca(countCalls * sizeof(RIL_Call *));
567 p_calls = (RIL_Call *)alloca(countCalls * sizeof(RIL_Call));
568 memset (p_calls, 0, countCalls * sizeof(RIL_Call));
The Android Open Source Project00f06fc2009-03-03 19:32:15 -0800569
570 /* init the pointer array */
571 for(i = 0; i < countCalls ; i++) {
572 pp_calls[i] = &(p_calls[i]);
573 }
574
575 for (countValidCalls = 0, p_cur = p_response->p_intermediates
576 ; p_cur != NULL
577 ; p_cur = p_cur->p_next
578 ) {
579 err = callFromCLCCLine(p_cur->line, p_calls + countValidCalls);
580
581 if (err != 0) {
582 continue;
583 }
584
585#ifdef WORKAROUND_ERRONEOUS_ANSWER
586 if (p_calls[countValidCalls].state == RIL_CALL_INCOMING
587 || p_calls[countValidCalls].state == RIL_CALL_WAITING
588 ) {
589 s_incomingOrWaitingLine = p_calls[countValidCalls].index;
590 }
591#endif /*WORKAROUND_ERRONEOUS_ANSWER*/
592
593 if (p_calls[countValidCalls].state != RIL_CALL_ACTIVE
594 && p_calls[countValidCalls].state != RIL_CALL_HOLDING
595 ) {
596 needRepoll = 1;
597 }
598
599 countValidCalls++;
600 }
601
602#ifdef WORKAROUND_ERRONEOUS_ANSWER
603 // Basically:
604 // A call was incoming or waiting
605 // Now it's marked as active
606 // But we never answered it
607 //
608 // This is probably a bug, and the call will probably
609 // disappear from the call list in the next poll
610 if (prevIncomingOrWaitingLine >= 0
611 && s_incomingOrWaitingLine < 0
612 && s_expectAnswer == 0
613 ) {
614 for (i = 0; i < countValidCalls ; i++) {
615
616 if (p_calls[i].index == prevIncomingOrWaitingLine
617 && p_calls[i].state == RIL_CALL_ACTIVE
618 && s_repollCallsCount < REPOLL_CALLS_COUNT_MAX
619 ) {
620 LOGI(
621 "Hit WORKAROUND_ERRONOUS_ANSWER case."
622 " Repoll count: %d\n", s_repollCallsCount);
623 s_repollCallsCount++;
624 goto error;
625 }
626 }
627 }
628
629 s_expectAnswer = 0;
630 s_repollCallsCount = 0;
631#endif /*WORKAROUND_ERRONEOUS_ANSWER*/
632
Wink Saville3d54e742009-05-18 18:00:44 -0700633 RIL_onRequestComplete(t, RIL_E_SUCCESS, pp_calls,
634 countValidCalls * sizeof (RIL_Call *));
The Android Open Source Project00f06fc2009-03-03 19:32:15 -0800635
636 at_response_free(p_response);
637
638#ifdef POLL_CALL_STATE
639 if (countValidCalls) { // We don't seem to get a "NO CARRIER" message from
640 // smd, so we're forced to poll until the call ends.
641#else
642 if (needRepoll) {
643#endif
644 RIL_requestTimedCallback (sendCallStateChanged, NULL, &TIMEVAL_CALLSTATEPOLL);
645 }
646
647 return;
648error:
649 RIL_onRequestComplete(t, RIL_E_GENERIC_FAILURE, NULL, 0);
650 at_response_free(p_response);
651}
652
653static void requestDial(void *data, size_t datalen, RIL_Token t)
654{
655 RIL_Dial *p_dial;
656 char *cmd;
657 const char *clir;
658 int ret;
659
660 p_dial = (RIL_Dial *)data;
661
662 switch (p_dial->clir) {
663 case 1: clir = "I"; break; /*invocation*/
664 case 2: clir = "i"; break; /*suppression*/
665 default:
666 case 0: clir = ""; break; /*subscription default*/
667 }
668
669 asprintf(&cmd, "ATD%s%s;", p_dial->address, clir);
670
671 ret = at_send_command(cmd, NULL);
672
673 free(cmd);
674
675 /* success or failure is ignored by the upper layer here.
676 it will call GET_CURRENT_CALLS and determine success that way */
677 RIL_onRequestComplete(t, RIL_E_SUCCESS, NULL, 0);
678}
679
680static void requestWriteSmsToSim(void *data, size_t datalen, RIL_Token t)
681{
682 RIL_SMS_WriteArgs *p_args;
683 char *cmd;
684 int length;
685 int err;
686 ATResponse *p_response = NULL;
687
688 p_args = (RIL_SMS_WriteArgs *)data;
689
690 length = strlen(p_args->pdu)/2;
691 asprintf(&cmd, "AT+CMGW=%d,%d", length, p_args->status);
692
693 err = at_send_command_sms(cmd, p_args->pdu, "+CMGW:", &p_response);
694
695 if (err != 0 || p_response->success == 0) goto error;
696
697 RIL_onRequestComplete(t, RIL_E_SUCCESS, NULL, 0);
698 at_response_free(p_response);
699
700 return;
701error:
702 RIL_onRequestComplete(t, RIL_E_GENERIC_FAILURE, NULL, 0);
703 at_response_free(p_response);
704}
705
706static void requestHangup(void *data, size_t datalen, RIL_Token t)
707{
708 int *p_line;
709
710 int ret;
711 char *cmd;
712
713 p_line = (int *)data;
714
715 // 3GPP 22.030 6.5.5
716 // "Releases a specific active call X"
717 asprintf(&cmd, "AT+CHLD=1%d", p_line[0]);
718
719 ret = at_send_command(cmd, NULL);
720
721 free(cmd);
722
723 /* success or failure is ignored by the upper layer here.
724 it will call GET_CURRENT_CALLS and determine success that way */
725 RIL_onRequestComplete(t, RIL_E_SUCCESS, NULL, 0);
726}
727
728static void requestSignalStrength(void *data, size_t datalen, RIL_Token t)
729{
730 ATResponse *p_response = NULL;
731 int err;
732 int response[2];
733 char *line;
734
735 err = at_send_command_singleline("AT+CSQ", "+CSQ:", &p_response);
736
737 if (err < 0 || p_response->success == 0) {
738 RIL_onRequestComplete(t, RIL_E_GENERIC_FAILURE, NULL, 0);
739 goto error;
740 }
741
742 line = p_response->p_intermediates->line;
743
744 err = at_tok_start(&line);
745 if (err < 0) goto error;
746
747 err = at_tok_nextint(&line, &(response[0]));
748 if (err < 0) goto error;
749
750 err = at_tok_nextint(&line, &(response[1]));
751 if (err < 0) goto error;
752
753 RIL_onRequestComplete(t, RIL_E_SUCCESS, response, sizeof(response));
754
755 at_response_free(p_response);
756 return;
757
758error:
759 LOGE("requestSignalStrength must never return an error when radio is on");
760 RIL_onRequestComplete(t, RIL_E_GENERIC_FAILURE, NULL, 0);
761 at_response_free(p_response);
762}
763
764static void requestRegistrationState(int request, void *data,
765 size_t datalen, RIL_Token t)
766{
767 int err;
768 int response[4];
769 char * responseStr[4];
770 ATResponse *p_response = NULL;
771 const char *cmd;
772 const char *prefix;
773 char *line, *p;
774 int commas;
775 int skip;
776 int count = 3;
777
778
Wink Saville2c1fb3a2011-03-19 13:42:45 -0700779 if (request == RIL_REQUEST_VOICE_REGISTRATION_STATE) {
The Android Open Source Project00f06fc2009-03-03 19:32:15 -0800780 cmd = "AT+CREG?";
781 prefix = "+CREG:";
Wink Saville2c1fb3a2011-03-19 13:42:45 -0700782 } else if (request == RIL_REQUEST_DATA_REGISTRATION_STATE) {
The Android Open Source Project00f06fc2009-03-03 19:32:15 -0800783 cmd = "AT+CGREG?";
784 prefix = "+CGREG:";
785 } else {
786 assert(0);
787 goto error;
788 }
789
790 err = at_send_command_singleline(cmd, prefix, &p_response);
791
792 if (err != 0) goto error;
793
794 line = p_response->p_intermediates->line;
795
796 err = at_tok_start(&line);
797 if (err < 0) goto error;
798
799 /* Ok you have to be careful here
800 * The solicited version of the CREG response is
801 * +CREG: n, stat, [lac, cid]
802 * and the unsolicited version is
803 * +CREG: stat, [lac, cid]
804 * The <n> parameter is basically "is unsolicited creg on?"
805 * which it should always be
806 *
807 * Now we should normally get the solicited version here,
808 * but the unsolicited version could have snuck in
809 * so we have to handle both
810 *
811 * Also since the LAC and CID are only reported when registered,
812 * we can have 1, 2, 3, or 4 arguments here
813 *
814 * finally, a +CGREG: answer may have a fifth value that corresponds
815 * to the network type, as in;
816 *
817 * +CGREG: n, stat [,lac, cid [,networkType]]
818 */
819
820 /* count number of commas */
821 commas = 0;
822 for (p = line ; *p != '\0' ;p++) {
823 if (*p == ',') commas++;
824 }
825
826 switch (commas) {
827 case 0: /* +CREG: <stat> */
828 err = at_tok_nextint(&line, &response[0]);
829 if (err < 0) goto error;
830 response[1] = -1;
831 response[2] = -1;
832 break;
833
834 case 1: /* +CREG: <n>, <stat> */
835 err = at_tok_nextint(&line, &skip);
836 if (err < 0) goto error;
837 err = at_tok_nextint(&line, &response[0]);
838 if (err < 0) goto error;
839 response[1] = -1;
840 response[2] = -1;
841 if (err < 0) goto error;
842 break;
843
844 case 2: /* +CREG: <stat>, <lac>, <cid> */
845 err = at_tok_nextint(&line, &response[0]);
846 if (err < 0) goto error;
847 err = at_tok_nexthexint(&line, &response[1]);
848 if (err < 0) goto error;
849 err = at_tok_nexthexint(&line, &response[2]);
850 if (err < 0) goto error;
851 break;
852 case 3: /* +CREG: <n>, <stat>, <lac>, <cid> */
853 err = at_tok_nextint(&line, &skip);
854 if (err < 0) goto error;
855 err = at_tok_nextint(&line, &response[0]);
856 if (err < 0) goto error;
857 err = at_tok_nexthexint(&line, &response[1]);
858 if (err < 0) goto error;
859 err = at_tok_nexthexint(&line, &response[2]);
860 if (err < 0) goto error;
861 break;
862 /* special case for CGREG, there is a fourth parameter
863 * that is the network type (unknown/gprs/edge/umts)
864 */
865 case 4: /* +CGREG: <n>, <stat>, <lac>, <cid>, <networkType> */
866 err = at_tok_nextint(&line, &skip);
867 if (err < 0) goto error;
868 err = at_tok_nextint(&line, &response[0]);
869 if (err < 0) goto error;
870 err = at_tok_nexthexint(&line, &response[1]);
871 if (err < 0) goto error;
872 err = at_tok_nexthexint(&line, &response[2]);
873 if (err < 0) goto error;
874 err = at_tok_nexthexint(&line, &response[3]);
875 if (err < 0) goto error;
876 count = 4;
877 break;
878 default:
879 goto error;
880 }
881
882 asprintf(&responseStr[0], "%d", response[0]);
John Wang6f189a62009-06-30 13:12:53 -0700883 asprintf(&responseStr[1], "%x", response[1]);
884 asprintf(&responseStr[2], "%x", response[2]);
The Android Open Source Project00f06fc2009-03-03 19:32:15 -0800885
886 if (count > 3)
887 asprintf(&responseStr[3], "%d", response[3]);
888
889 RIL_onRequestComplete(t, RIL_E_SUCCESS, responseStr, count*sizeof(char*));
890 at_response_free(p_response);
891
892 return;
893error:
894 LOGE("requestRegistrationState must never return an error when radio is on");
895 RIL_onRequestComplete(t, RIL_E_GENERIC_FAILURE, NULL, 0);
896 at_response_free(p_response);
897}
898
899static void requestOperator(void *data, size_t datalen, RIL_Token t)
900{
901 int err;
902 int i;
903 int skip;
904 ATLine *p_cur;
905 char *response[3];
906
907 memset(response, 0, sizeof(response));
908
909 ATResponse *p_response = NULL;
910
911 err = at_send_command_multiline(
912 "AT+COPS=3,0;+COPS?;+COPS=3,1;+COPS?;+COPS=3,2;+COPS?",
913 "+COPS:", &p_response);
914
915 /* we expect 3 lines here:
916 * +COPS: 0,0,"T - Mobile"
917 * +COPS: 0,1,"TMO"
918 * +COPS: 0,2,"310170"
919 */
920
921 if (err != 0) goto error;
922
923 for (i = 0, p_cur = p_response->p_intermediates
924 ; p_cur != NULL
925 ; p_cur = p_cur->p_next, i++
926 ) {
927 char *line = p_cur->line;
928
929 err = at_tok_start(&line);
930 if (err < 0) goto error;
931
932 err = at_tok_nextint(&line, &skip);
933 if (err < 0) goto error;
934
935 // If we're unregistered, we may just get
936 // a "+COPS: 0" response
937 if (!at_tok_hasmore(&line)) {
938 response[i] = NULL;
939 continue;
940 }
941
942 err = at_tok_nextint(&line, &skip);
943 if (err < 0) goto error;
944
945 // a "+COPS: 0, n" response is also possible
946 if (!at_tok_hasmore(&line)) {
947 response[i] = NULL;
948 continue;
949 }
950
951 err = at_tok_nextstr(&line, &(response[i]));
952 if (err < 0) goto error;
953 }
954
955 if (i != 3) {
956 /* expect 3 lines exactly */
957 goto error;
958 }
959
960 RIL_onRequestComplete(t, RIL_E_SUCCESS, response, sizeof(response));
961 at_response_free(p_response);
962
963 return;
964error:
965 LOGE("requestOperator must not return error when radio is on");
966 RIL_onRequestComplete(t, RIL_E_GENERIC_FAILURE, NULL, 0);
967 at_response_free(p_response);
968}
969
970static void requestSendSMS(void *data, size_t datalen, RIL_Token t)
971{
972 int err;
973 const char *smsc;
974 const char *pdu;
975 int tpLayerLength;
976 char *cmd1, *cmd2;
977 RIL_SMS_Response response;
978 ATResponse *p_response = NULL;
979
980 smsc = ((const char **)data)[0];
981 pdu = ((const char **)data)[1];
982
983 tpLayerLength = strlen(pdu)/2;
984
985 // "NULL for default SMSC"
986 if (smsc == NULL) {
987 smsc= "00";
988 }
989
990 asprintf(&cmd1, "AT+CMGS=%d", tpLayerLength);
991 asprintf(&cmd2, "%s%s", smsc, pdu);
992
993 err = at_send_command_sms(cmd1, cmd2, "+CMGS:", &p_response);
994
995 if (err != 0 || p_response->success == 0) goto error;
996
997 memset(&response, 0, sizeof(response));
998
999 /* FIXME fill in messageRef and ackPDU */
1000
1001 RIL_onRequestComplete(t, RIL_E_SUCCESS, &response, sizeof(response));
1002 at_response_free(p_response);
1003
1004 return;
1005error:
1006 RIL_onRequestComplete(t, RIL_E_GENERIC_FAILURE, NULL, 0);
1007 at_response_free(p_response);
1008}
1009
Wink Savillef4c4d362009-04-02 01:37:03 -07001010static void requestSetupDataCall(void *data, size_t datalen, RIL_Token t)
The Android Open Source Project00f06fc2009-03-03 19:32:15 -08001011{
1012 const char *apn;
1013 char *cmd;
1014 int err;
1015 ATResponse *p_response = NULL;
The Android Open Source Project00f06fc2009-03-03 19:32:15 -08001016
Wink Savillef4c4d362009-04-02 01:37:03 -07001017 apn = ((const char **)data)[2];
The Android Open Source Project00f06fc2009-03-03 19:32:15 -08001018
1019#ifdef USE_TI_COMMANDS
1020 // Config for multislot class 10 (probably default anyway eh?)
1021 err = at_send_command("AT%CPRIM=\"GMM\",\"CONFIG MULTISLOT_CLASS=<10>\"",
1022 NULL);
1023
1024 err = at_send_command("AT%DATA=2,\"UART\",1,,\"SER\",\"UART\",0", NULL);
1025#endif /* USE_TI_COMMANDS */
1026
1027 int fd, qmistatus;
1028 size_t cur = 0;
1029 size_t len;
1030 ssize_t written, rlen;
1031 char status[32] = {0};
1032 int retry = 10;
Lorenzo Colitti4f81dcf2010-09-01 19:38:57 -07001033 const char *pdp_type;
The Android Open Source Project00f06fc2009-03-03 19:32:15 -08001034
1035 LOGD("requesting data connection to APN '%s'", apn);
1036
1037 fd = open ("/dev/qmi", O_RDWR);
1038 if (fd >= 0) { /* the device doesn't exist on the emulator */
1039
Lorenzo Colitti4f81dcf2010-09-01 19:38:57 -07001040 LOGD("opened the qmi device\n");
1041 asprintf(&cmd, "up:%s", apn);
1042 len = strlen(cmd);
The Android Open Source Project00f06fc2009-03-03 19:32:15 -08001043
Lorenzo Colitti4f81dcf2010-09-01 19:38:57 -07001044 while (cur < len) {
1045 do {
1046 written = write (fd, cmd + cur, len - cur);
1047 } while (written < 0 && errno == EINTR);
The Android Open Source Project00f06fc2009-03-03 19:32:15 -08001048
Lorenzo Colitti4f81dcf2010-09-01 19:38:57 -07001049 if (written < 0) {
The Android Open Source Project00f06fc2009-03-03 19:32:15 -08001050 LOGE("### ERROR writing to /dev/qmi");
1051 close(fd);
1052 goto error;
1053 }
1054
1055 cur += written;
1056 }
1057
1058 // wait for interface to come online
1059
1060 do {
1061 sleep(1);
1062 do {
1063 rlen = read(fd, status, 31);
1064 } while (rlen < 0 && errno == EINTR);
1065
1066 if (rlen < 0) {
1067 LOGE("### ERROR reading from /dev/qmi");
1068 close(fd);
1069 goto error;
1070 } else {
1071 status[rlen] = '\0';
1072 LOGD("### status: %s", status);
1073 }
1074 } while (strncmp(status, "STATE=up", 8) && strcmp(status, "online") && --retry);
1075
1076 close(fd);
1077
1078 if (retry == 0) {
1079 LOGE("### Failed to get data connection up\n");
Lorenzo Colitti4f81dcf2010-09-01 19:38:57 -07001080 goto error;
1081 }
The Android Open Source Project00f06fc2009-03-03 19:32:15 -08001082
1083 qmistatus = system("netcfg rmnet0 dhcp");
1084
1085 LOGD("netcfg rmnet0 dhcp: status %d\n", qmistatus);
1086
Lorenzo Colitti4f81dcf2010-09-01 19:38:57 -07001087 if (qmistatus < 0) goto error;
The Android Open Source Project00f06fc2009-03-03 19:32:15 -08001088
Lorenzo Colitti4f81dcf2010-09-01 19:38:57 -07001089 } else {
The Android Open Source Project00f06fc2009-03-03 19:32:15 -08001090
Lorenzo Colitti4f81dcf2010-09-01 19:38:57 -07001091 if (datalen > 6 * sizeof(char *)) {
1092 pdp_type = ((const char **)data)[6];
1093 } else {
1094 pdp_type = "IP";
1095 }
The Android Open Source Project00f06fc2009-03-03 19:32:15 -08001096
David 'Digit' Turneraf1298d2011-02-04 13:36:47 +01001097 asprintf(&cmd, "AT+CGDCONT=1,\"%s\",\"%s\",,0,0", pdp_type, apn);
Lorenzo Colitti4f81dcf2010-09-01 19:38:57 -07001098 //FIXME check for error here
1099 err = at_send_command(cmd, NULL);
1100 free(cmd);
The Android Open Source Project00f06fc2009-03-03 19:32:15 -08001101
Lorenzo Colitti4f81dcf2010-09-01 19:38:57 -07001102 // Set required QoS params to default
1103 err = at_send_command("AT+CGQREQ=1", NULL);
The Android Open Source Project00f06fc2009-03-03 19:32:15 -08001104
Lorenzo Colitti4f81dcf2010-09-01 19:38:57 -07001105 // Set minimum QoS params to default
1106 err = at_send_command("AT+CGQMIN=1", NULL);
The Android Open Source Project00f06fc2009-03-03 19:32:15 -08001107
Lorenzo Colitti4f81dcf2010-09-01 19:38:57 -07001108 // packet-domain event reporting
1109 err = at_send_command("AT+CGEREP=1,0", NULL);
The Android Open Source Project00f06fc2009-03-03 19:32:15 -08001110
Lorenzo Colitti4f81dcf2010-09-01 19:38:57 -07001111 // Hangup anything that's happening there now
1112 err = at_send_command("AT+CGACT=1,0", NULL);
The Android Open Source Project00f06fc2009-03-03 19:32:15 -08001113
Lorenzo Colitti4f81dcf2010-09-01 19:38:57 -07001114 // Start data on PDP context 1
1115 err = at_send_command("ATD*99***1#", &p_response);
1116
1117 if (err < 0 || p_response->success == 0) {
1118 goto error;
1119 }
The Android Open Source Project00f06fc2009-03-03 19:32:15 -08001120 }
1121
Wink Saville43808972011-01-13 17:39:51 -08001122 requestOrSendDataCallList(&t);
1123
The Android Open Source Project00f06fc2009-03-03 19:32:15 -08001124 at_response_free(p_response);
1125
1126 return;
1127error:
1128 RIL_onRequestComplete(t, RIL_E_GENERIC_FAILURE, NULL, 0);
1129 at_response_free(p_response);
1130
1131}
1132
1133static void requestSMSAcknowledge(void *data, size_t datalen, RIL_Token t)
1134{
1135 int ackSuccess;
1136 int err;
1137
1138 ackSuccess = ((int *)data)[0];
1139
1140 if (ackSuccess == 1) {
1141 err = at_send_command("AT+CNMA=1", NULL);
1142 } else if (ackSuccess == 0) {
1143 err = at_send_command("AT+CNMA=2", NULL);
1144 } else {
1145 LOGE("unsupported arg to RIL_REQUEST_SMS_ACKNOWLEDGE\n");
1146 goto error;
1147 }
1148
1149 RIL_onRequestComplete(t, RIL_E_SUCCESS, NULL, 0);
1150error:
1151 RIL_onRequestComplete(t, RIL_E_GENERIC_FAILURE, NULL, 0);
1152
1153}
1154
1155static void requestSIM_IO(void *data, size_t datalen, RIL_Token t)
1156{
1157 ATResponse *p_response = NULL;
1158 RIL_SIM_IO_Response sr;
1159 int err;
1160 char *cmd = NULL;
Wink Saville2c1fb3a2011-03-19 13:42:45 -07001161 RIL_SIM_IO_v6 *p_args;
The Android Open Source Project00f06fc2009-03-03 19:32:15 -08001162 char *line;
1163
1164 memset(&sr, 0, sizeof(sr));
1165
Wink Saville2c1fb3a2011-03-19 13:42:45 -07001166 p_args = (RIL_SIM_IO_v6 *)data;
The Android Open Source Project00f06fc2009-03-03 19:32:15 -08001167
1168 /* FIXME handle pin2 */
1169
1170 if (p_args->data == NULL) {
1171 asprintf(&cmd, "AT+CRSM=%d,%d,%d,%d,%d",
1172 p_args->command, p_args->fileid,
1173 p_args->p1, p_args->p2, p_args->p3);
1174 } else {
1175 asprintf(&cmd, "AT+CRSM=%d,%d,%d,%d,%d,%s",
1176 p_args->command, p_args->fileid,
1177 p_args->p1, p_args->p2, p_args->p3, p_args->data);
1178 }
1179
1180 err = at_send_command_singleline(cmd, "+CRSM:", &p_response);
1181
1182 if (err < 0 || p_response->success == 0) {
1183 goto error;
1184 }
1185
1186 line = p_response->p_intermediates->line;
1187
1188 err = at_tok_start(&line);
1189 if (err < 0) goto error;
1190
1191 err = at_tok_nextint(&line, &(sr.sw1));
1192 if (err < 0) goto error;
1193
1194 err = at_tok_nextint(&line, &(sr.sw2));
1195 if (err < 0) goto error;
1196
1197 if (at_tok_hasmore(&line)) {
1198 err = at_tok_nextstr(&line, &(sr.simResponse));
1199 if (err < 0) goto error;
1200 }
1201
1202 RIL_onRequestComplete(t, RIL_E_SUCCESS, &sr, sizeof(sr));
1203 at_response_free(p_response);
1204 free(cmd);
1205
1206 return;
1207error:
1208 RIL_onRequestComplete(t, RIL_E_GENERIC_FAILURE, NULL, 0);
1209 at_response_free(p_response);
1210 free(cmd);
1211
1212}
1213
1214static void requestEnterSimPin(void* data, size_t datalen, RIL_Token t)
1215{
1216 ATResponse *p_response = NULL;
1217 int err;
1218 char* cmd = NULL;
1219 const char** strings = (const char**)data;;
1220
1221 if ( datalen == sizeof(char*) ) {
1222 asprintf(&cmd, "AT+CPIN=%s", strings[0]);
1223 } else if ( datalen == 2*sizeof(char*) ) {
1224 asprintf(&cmd, "AT+CPIN=%s,%s", strings[0], strings[1]);
1225 } else
1226 goto error;
1227
1228 err = at_send_command_singleline(cmd, "+CPIN:", &p_response);
1229 free(cmd);
1230
1231 if (err < 0 || p_response->success == 0) {
1232error:
1233 RIL_onRequestComplete(t, RIL_E_PASSWORD_INCORRECT, NULL, 0);
1234 } else {
1235 RIL_onRequestComplete(t, RIL_E_SUCCESS, NULL, 0);
1236 }
1237 at_response_free(p_response);
1238}
1239
1240
1241static void requestSendUSSD(void *data, size_t datalen, RIL_Token t)
1242{
1243 const char *ussdRequest;
1244
1245 ussdRequest = (char *)(data);
1246
1247
1248 RIL_onRequestComplete(t, RIL_E_REQUEST_NOT_SUPPORTED, NULL, 0);
1249
1250// @@@ TODO
1251
1252}
1253
1254
1255/*** Callback methods from the RIL library to us ***/
1256
1257/**
1258 * Call from RIL to us to make a RIL_REQUEST
1259 *
1260 * Must be completed with a call to RIL_onRequestComplete()
1261 *
1262 * RIL_onRequestComplete() may be called from any thread, before or after
1263 * this function returns.
1264 *
1265 * Will always be called from the same thread, so returning here implies
1266 * that the radio is ready to process another command (whether or not
1267 * the previous command has completed).
1268 */
1269static void
1270onRequest (int request, void *data, size_t datalen, RIL_Token t)
1271{
1272 ATResponse *p_response;
1273 int err;
1274
1275 LOGD("onRequest: %s", requestToString(request));
1276
1277 /* Ignore all requests except RIL_REQUEST_GET_SIM_STATUS
1278 * when RADIO_STATE_UNAVAILABLE.
1279 */
1280 if (sState == RADIO_STATE_UNAVAILABLE
1281 && request != RIL_REQUEST_GET_SIM_STATUS
1282 ) {
1283 RIL_onRequestComplete(t, RIL_E_RADIO_NOT_AVAILABLE, NULL, 0);
1284 return;
1285 }
1286
1287 /* Ignore all non-power requests when RADIO_STATE_OFF
1288 * (except RIL_REQUEST_GET_SIM_STATUS)
1289 */
1290 if (sState == RADIO_STATE_OFF
1291 && !(request == RIL_REQUEST_RADIO_POWER
1292 || request == RIL_REQUEST_GET_SIM_STATUS)
1293 ) {
1294 RIL_onRequestComplete(t, RIL_E_RADIO_NOT_AVAILABLE, NULL, 0);
1295 return;
1296 }
1297
1298 switch (request) {
1299 case RIL_REQUEST_GET_SIM_STATUS: {
Wink Saville2c1fb3a2011-03-19 13:42:45 -07001300 RIL_CardStatus_v6 *p_card_status;
Wink Savillef6aa7c12009-04-30 14:20:52 -07001301 char *p_buffer;
1302 int buffer_size;
The Android Open Source Project00f06fc2009-03-03 19:32:15 -08001303
Wink Savillef6aa7c12009-04-30 14:20:52 -07001304 int result = getCardStatus(&p_card_status);
1305 if (result == RIL_E_SUCCESS) {
1306 p_buffer = (char *)p_card_status;
1307 buffer_size = sizeof(*p_card_status);
1308 } else {
1309 p_buffer = NULL;
1310 buffer_size = 0;
1311 }
1312 RIL_onRequestComplete(t, result, p_buffer, buffer_size);
1313 freeCardStatus(p_card_status);
The Android Open Source Project00f06fc2009-03-03 19:32:15 -08001314 break;
1315 }
1316 case RIL_REQUEST_GET_CURRENT_CALLS:
1317 requestGetCurrentCalls(data, datalen, t);
1318 break;
1319 case RIL_REQUEST_DIAL:
1320 requestDial(data, datalen, t);
1321 break;
1322 case RIL_REQUEST_HANGUP:
1323 requestHangup(data, datalen, t);
1324 break;
1325 case RIL_REQUEST_HANGUP_WAITING_OR_BACKGROUND:
1326 // 3GPP 22.030 6.5.5
1327 // "Releases all held calls or sets User Determined User Busy
1328 // (UDUB) for a waiting call."
1329 at_send_command("AT+CHLD=0", NULL);
1330
1331 /* success or failure is ignored by the upper layer here.
1332 it will call GET_CURRENT_CALLS and determine success that way */
1333 RIL_onRequestComplete(t, RIL_E_SUCCESS, NULL, 0);
1334 break;
1335 case RIL_REQUEST_HANGUP_FOREGROUND_RESUME_BACKGROUND:
1336 // 3GPP 22.030 6.5.5
1337 // "Releases all active calls (if any exist) and accepts
1338 // the other (held or waiting) call."
1339 at_send_command("AT+CHLD=1", NULL);
1340
1341 /* success or failure is ignored by the upper layer here.
1342 it will call GET_CURRENT_CALLS and determine success that way */
1343 RIL_onRequestComplete(t, RIL_E_SUCCESS, NULL, 0);
1344 break;
1345 case RIL_REQUEST_SWITCH_WAITING_OR_HOLDING_AND_ACTIVE:
1346 // 3GPP 22.030 6.5.5
1347 // "Places all active calls (if any exist) on hold and accepts
1348 // the other (held or waiting) call."
1349 at_send_command("AT+CHLD=2", NULL);
1350
1351#ifdef WORKAROUND_ERRONEOUS_ANSWER
1352 s_expectAnswer = 1;
1353#endif /* WORKAROUND_ERRONEOUS_ANSWER */
1354
1355 /* success or failure is ignored by the upper layer here.
1356 it will call GET_CURRENT_CALLS and determine success that way */
1357 RIL_onRequestComplete(t, RIL_E_SUCCESS, NULL, 0);
1358 break;
1359 case RIL_REQUEST_ANSWER:
1360 at_send_command("ATA", NULL);
1361
1362#ifdef WORKAROUND_ERRONEOUS_ANSWER
1363 s_expectAnswer = 1;
1364#endif /* WORKAROUND_ERRONEOUS_ANSWER */
1365
1366 /* success or failure is ignored by the upper layer here.
1367 it will call GET_CURRENT_CALLS and determine success that way */
1368 RIL_onRequestComplete(t, RIL_E_SUCCESS, NULL, 0);
1369 break;
1370 case RIL_REQUEST_CONFERENCE:
1371 // 3GPP 22.030 6.5.5
1372 // "Adds a held call to the conversation"
1373 at_send_command("AT+CHLD=3", NULL);
1374
1375 /* success or failure is ignored by the upper layer here.
1376 it will call GET_CURRENT_CALLS and determine success that way */
1377 RIL_onRequestComplete(t, RIL_E_SUCCESS, NULL, 0);
1378 break;
1379 case RIL_REQUEST_UDUB:
1380 /* user determined user busy */
1381 /* sometimes used: ATH */
1382 at_send_command("ATH", NULL);
1383
1384 /* success or failure is ignored by the upper layer here.
1385 it will call GET_CURRENT_CALLS and determine success that way */
1386 RIL_onRequestComplete(t, RIL_E_SUCCESS, NULL, 0);
1387 break;
1388
1389 case RIL_REQUEST_SEPARATE_CONNECTION:
1390 {
1391 char cmd[12];
1392 int party = ((int*)data)[0];
1393
1394 // Make sure that party is in a valid range.
1395 // (Note: The Telephony middle layer imposes a range of 1 to 7.
1396 // It's sufficient for us to just make sure it's single digit.)
1397 if (party > 0 && party < 10) {
1398 sprintf(cmd, "AT+CHLD=2%d", party);
1399 at_send_command(cmd, NULL);
1400 RIL_onRequestComplete(t, RIL_E_SUCCESS, NULL, 0);
1401 } else {
1402 RIL_onRequestComplete(t, RIL_E_GENERIC_FAILURE, NULL, 0);
1403 }
1404 }
1405 break;
1406
1407 case RIL_REQUEST_SIGNAL_STRENGTH:
1408 requestSignalStrength(data, datalen, t);
1409 break;
Wink Saville2c1fb3a2011-03-19 13:42:45 -07001410 case RIL_REQUEST_VOICE_REGISTRATION_STATE:
1411 case RIL_REQUEST_DATA_REGISTRATION_STATE:
The Android Open Source Project00f06fc2009-03-03 19:32:15 -08001412 requestRegistrationState(request, data, datalen, t);
1413 break;
1414 case RIL_REQUEST_OPERATOR:
1415 requestOperator(data, datalen, t);
1416 break;
1417 case RIL_REQUEST_RADIO_POWER:
1418 requestRadioPower(data, datalen, t);
1419 break;
1420 case RIL_REQUEST_DTMF: {
1421 char c = ((char *)data)[0];
1422 char *cmd;
1423 asprintf(&cmd, "AT+VTS=%c", (int)c);
1424 at_send_command(cmd, NULL);
1425 free(cmd);
1426 RIL_onRequestComplete(t, RIL_E_SUCCESS, NULL, 0);
1427 break;
1428 }
1429 case RIL_REQUEST_SEND_SMS:
1430 requestSendSMS(data, datalen, t);
1431 break;
Wink Savillef4c4d362009-04-02 01:37:03 -07001432 case RIL_REQUEST_SETUP_DATA_CALL:
1433 requestSetupDataCall(data, datalen, t);
The Android Open Source Project00f06fc2009-03-03 19:32:15 -08001434 break;
1435 case RIL_REQUEST_SMS_ACKNOWLEDGE:
1436 requestSMSAcknowledge(data, datalen, t);
1437 break;
1438
1439 case RIL_REQUEST_GET_IMSI:
1440 p_response = NULL;
1441 err = at_send_command_numeric("AT+CIMI", &p_response);
1442
1443 if (err < 0 || p_response->success == 0) {
1444 RIL_onRequestComplete(t, RIL_E_GENERIC_FAILURE, NULL, 0);
1445 } else {
1446 RIL_onRequestComplete(t, RIL_E_SUCCESS,
1447 p_response->p_intermediates->line, sizeof(char *));
1448 }
1449 at_response_free(p_response);
1450 break;
1451
1452 case RIL_REQUEST_GET_IMEI:
1453 p_response = NULL;
1454 err = at_send_command_numeric("AT+CGSN", &p_response);
1455
1456 if (err < 0 || p_response->success == 0) {
1457 RIL_onRequestComplete(t, RIL_E_GENERIC_FAILURE, NULL, 0);
1458 } else {
1459 RIL_onRequestComplete(t, RIL_E_SUCCESS,
1460 p_response->p_intermediates->line, sizeof(char *));
1461 }
1462 at_response_free(p_response);
1463 break;
1464
1465 case RIL_REQUEST_SIM_IO:
1466 requestSIM_IO(data,datalen,t);
1467 break;
1468
1469 case RIL_REQUEST_SEND_USSD:
1470 requestSendUSSD(data, datalen, t);
1471 break;
1472
1473 case RIL_REQUEST_CANCEL_USSD:
1474 p_response = NULL;
1475 err = at_send_command_numeric("AT+CUSD=2", &p_response);
1476
1477 if (err < 0 || p_response->success == 0) {
1478 RIL_onRequestComplete(t, RIL_E_GENERIC_FAILURE, NULL, 0);
1479 } else {
1480 RIL_onRequestComplete(t, RIL_E_SUCCESS,
1481 p_response->p_intermediates->line, sizeof(char *));
1482 }
1483 at_response_free(p_response);
1484 break;
1485
1486 case RIL_REQUEST_SET_NETWORK_SELECTION_AUTOMATIC:
1487 at_send_command("AT+COPS=0", NULL);
1488 break;
1489
Wink Savillef4c4d362009-04-02 01:37:03 -07001490 case RIL_REQUEST_DATA_CALL_LIST:
1491 requestDataCallList(data, datalen, t);
The Android Open Source Project00f06fc2009-03-03 19:32:15 -08001492 break;
1493
1494 case RIL_REQUEST_QUERY_NETWORK_SELECTION_MODE:
1495 requestQueryNetworkSelectionMode(data, datalen, t);
1496 break;
1497
1498 case RIL_REQUEST_OEM_HOOK_RAW:
1499 // echo back data
1500 RIL_onRequestComplete(t, RIL_E_SUCCESS, data, datalen);
1501 break;
1502
1503
1504 case RIL_REQUEST_OEM_HOOK_STRINGS: {
1505 int i;
1506 const char ** cur;
1507
1508 LOGD("got OEM_HOOK_STRINGS: 0x%8p %lu", data, (long)datalen);
1509
1510
1511 for (i = (datalen / sizeof (char *)), cur = (const char **)data ;
1512 i > 0 ; cur++, i --) {
1513 LOGD("> '%s'", *cur);
1514 }
1515
1516 // echo back strings
1517 RIL_onRequestComplete(t, RIL_E_SUCCESS, data, datalen);
1518 break;
1519 }
1520
1521 case RIL_REQUEST_WRITE_SMS_TO_SIM:
1522 requestWriteSmsToSim(data, datalen, t);
1523 break;
1524
1525 case RIL_REQUEST_DELETE_SMS_ON_SIM: {
1526 char * cmd;
1527 p_response = NULL;
1528 asprintf(&cmd, "AT+CMGD=%d", ((int *)data)[0]);
1529 err = at_send_command(cmd, &p_response);
1530 free(cmd);
1531 if (err < 0 || p_response->success == 0) {
1532 RIL_onRequestComplete(t, RIL_E_GENERIC_FAILURE, NULL, 0);
1533 } else {
1534 RIL_onRequestComplete(t, RIL_E_SUCCESS, NULL, 0);
1535 }
1536 at_response_free(p_response);
1537 break;
1538 }
1539
1540 case RIL_REQUEST_ENTER_SIM_PIN:
1541 case RIL_REQUEST_ENTER_SIM_PUK:
1542 case RIL_REQUEST_ENTER_SIM_PIN2:
1543 case RIL_REQUEST_ENTER_SIM_PUK2:
1544 case RIL_REQUEST_CHANGE_SIM_PIN:
1545 case RIL_REQUEST_CHANGE_SIM_PIN2:
1546 requestEnterSimPin(data, datalen, t);
1547 break;
1548
1549 default:
1550 RIL_onRequestComplete(t, RIL_E_REQUEST_NOT_SUPPORTED, NULL, 0);
1551 break;
1552 }
1553}
1554
1555/**
1556 * Synchronous call from the RIL to us to return current radio state.
1557 * RADIO_STATE_UNAVAILABLE should be the initial state.
1558 */
1559static RIL_RadioState
1560currentState()
1561{
1562 return sState;
1563}
1564/**
1565 * Call from RIL to us to find out whether a specific request code
1566 * is supported by this implementation.
1567 *
1568 * Return 1 for "supported" and 0 for "unsupported"
1569 */
1570
1571static int
1572onSupports (int requestCode)
1573{
1574 //@@@ todo
1575
1576 return 1;
1577}
1578
1579static void onCancel (RIL_Token t)
1580{
1581 //@@@todo
1582
1583}
1584
1585static const char * getVersion(void)
1586{
1587 return "android reference-ril 1.0";
1588}
1589
1590static void
1591setRadioState(RIL_RadioState newState)
1592{
1593 RIL_RadioState oldState;
1594
1595 pthread_mutex_lock(&s_state_mutex);
1596
1597 oldState = sState;
1598
1599 if (s_closed > 0) {
1600 // If we're closed, the only reasonable state is
1601 // RADIO_STATE_UNAVAILABLE
1602 // This is here because things on the main thread
1603 // may attempt to change the radio state after the closed
1604 // event happened in another thread
1605 newState = RADIO_STATE_UNAVAILABLE;
1606 }
1607
1608 if (sState != newState || s_closed > 0) {
1609 sState = newState;
1610
1611 pthread_cond_broadcast (&s_state_cond);
1612 }
1613
1614 pthread_mutex_unlock(&s_state_mutex);
1615
1616
1617 /* do these outside of the mutex */
1618 if (sState != oldState) {
1619 RIL_onUnsolicitedResponse (RIL_UNSOL_RESPONSE_RADIO_STATE_CHANGED,
1620 NULL, 0);
1621
1622 /* FIXME onSimReady() and onRadioPowerOn() cannot be called
1623 * from the AT reader thread
1624 * Currently, this doesn't happen, but if that changes then these
1625 * will need to be dispatched on the request thread
1626 */
1627 if (sState == RADIO_STATE_SIM_READY) {
1628 onSIMReady();
1629 } else if (sState == RADIO_STATE_SIM_NOT_READY) {
1630 onRadioPowerOn();
1631 }
1632 }
1633}
1634
John Wang309ac292009-07-30 14:53:23 -07001635/** Returns SIM_NOT_READY on error */
David 'Digit' Turneraf1298d2011-02-04 13:36:47 +01001636static SIM_Status
The Android Open Source Project00f06fc2009-03-03 19:32:15 -08001637getSIMStatus()
1638{
1639 ATResponse *p_response = NULL;
1640 int err;
1641 int ret;
1642 char *cpinLine;
1643 char *cpinResult;
1644
1645 if (sState == RADIO_STATE_OFF || sState == RADIO_STATE_UNAVAILABLE) {
John Wang309ac292009-07-30 14:53:23 -07001646 ret = SIM_NOT_READY;
The Android Open Source Project00f06fc2009-03-03 19:32:15 -08001647 goto done;
1648 }
1649
1650 err = at_send_command_singleline("AT+CPIN?", "+CPIN:", &p_response);
1651
1652 if (err != 0) {
John Wang309ac292009-07-30 14:53:23 -07001653 ret = SIM_NOT_READY;
The Android Open Source Project00f06fc2009-03-03 19:32:15 -08001654 goto done;
1655 }
1656
1657 switch (at_get_cme_error(p_response)) {
1658 case CME_SUCCESS:
1659 break;
1660
1661 case CME_SIM_NOT_INSERTED:
John Wang309ac292009-07-30 14:53:23 -07001662 ret = SIM_ABSENT;
The Android Open Source Project00f06fc2009-03-03 19:32:15 -08001663 goto done;
1664
1665 default:
John Wang309ac292009-07-30 14:53:23 -07001666 ret = SIM_NOT_READY;
The Android Open Source Project00f06fc2009-03-03 19:32:15 -08001667 goto done;
1668 }
1669
1670 /* CPIN? has succeeded, now look at the result */
1671
1672 cpinLine = p_response->p_intermediates->line;
1673 err = at_tok_start (&cpinLine);
1674
1675 if (err < 0) {
John Wang309ac292009-07-30 14:53:23 -07001676 ret = SIM_NOT_READY;
The Android Open Source Project00f06fc2009-03-03 19:32:15 -08001677 goto done;
1678 }
1679
1680 err = at_tok_nextstr(&cpinLine, &cpinResult);
1681
1682 if (err < 0) {
John Wang309ac292009-07-30 14:53:23 -07001683 ret = SIM_NOT_READY;
The Android Open Source Project00f06fc2009-03-03 19:32:15 -08001684 goto done;
1685 }
1686
1687 if (0 == strcmp (cpinResult, "SIM PIN")) {
John Wang309ac292009-07-30 14:53:23 -07001688 ret = SIM_PIN;
The Android Open Source Project00f06fc2009-03-03 19:32:15 -08001689 goto done;
1690 } else if (0 == strcmp (cpinResult, "SIM PUK")) {
John Wang309ac292009-07-30 14:53:23 -07001691 ret = SIM_PUK;
The Android Open Source Project00f06fc2009-03-03 19:32:15 -08001692 goto done;
1693 } else if (0 == strcmp (cpinResult, "PH-NET PIN")) {
John Wang309ac292009-07-30 14:53:23 -07001694 return SIM_NETWORK_PERSONALIZATION;
The Android Open Source Project00f06fc2009-03-03 19:32:15 -08001695 } else if (0 != strcmp (cpinResult, "READY")) {
1696 /* we're treating unsupported lock types as "sim absent" */
John Wang309ac292009-07-30 14:53:23 -07001697 ret = SIM_ABSENT;
The Android Open Source Project00f06fc2009-03-03 19:32:15 -08001698 goto done;
1699 }
1700
1701 at_response_free(p_response);
1702 p_response = NULL;
1703 cpinResult = NULL;
1704
John Wang309ac292009-07-30 14:53:23 -07001705 ret = SIM_READY;
The Android Open Source Project00f06fc2009-03-03 19:32:15 -08001706
1707done:
1708 at_response_free(p_response);
1709 return ret;
1710}
1711
1712
1713/**
Wink Savillef6aa7c12009-04-30 14:20:52 -07001714 * Get the current card status.
1715 *
1716 * This must be freed using freeCardStatus.
1717 * @return: On success returns RIL_E_SUCCESS
1718 */
Wink Saville2c1fb3a2011-03-19 13:42:45 -07001719static int getCardStatus(RIL_CardStatus_v6 **pp_card_status) {
Wink Savillef6aa7c12009-04-30 14:20:52 -07001720 static RIL_AppStatus app_status_array[] = {
John Wang309ac292009-07-30 14:53:23 -07001721 // SIM_ABSENT = 0
Wink Savillef6aa7c12009-04-30 14:20:52 -07001722 { RIL_APPTYPE_UNKNOWN, RIL_APPSTATE_UNKNOWN, RIL_PERSOSUBSTATE_UNKNOWN,
1723 NULL, NULL, 0, RIL_PINSTATE_UNKNOWN, RIL_PINSTATE_UNKNOWN },
John Wang309ac292009-07-30 14:53:23 -07001724 // SIM_NOT_READY = 1
Wink Savillef6aa7c12009-04-30 14:20:52 -07001725 { RIL_APPTYPE_SIM, RIL_APPSTATE_DETECTED, RIL_PERSOSUBSTATE_UNKNOWN,
1726 NULL, NULL, 0, RIL_PINSTATE_UNKNOWN, RIL_PINSTATE_UNKNOWN },
John Wang309ac292009-07-30 14:53:23 -07001727 // SIM_READY = 2
Wink Savillef6aa7c12009-04-30 14:20:52 -07001728 { RIL_APPTYPE_SIM, RIL_APPSTATE_READY, RIL_PERSOSUBSTATE_READY,
1729 NULL, NULL, 0, RIL_PINSTATE_UNKNOWN, RIL_PINSTATE_UNKNOWN },
John Wang309ac292009-07-30 14:53:23 -07001730 // SIM_PIN = 3
Wink Savillef6aa7c12009-04-30 14:20:52 -07001731 { RIL_APPTYPE_SIM, RIL_APPSTATE_PIN, RIL_PERSOSUBSTATE_UNKNOWN,
1732 NULL, NULL, 0, RIL_PINSTATE_ENABLED_NOT_VERIFIED, RIL_PINSTATE_UNKNOWN },
John Wang309ac292009-07-30 14:53:23 -07001733 // SIM_PUK = 4
Wink Savillef6aa7c12009-04-30 14:20:52 -07001734 { RIL_APPTYPE_SIM, RIL_APPSTATE_PUK, RIL_PERSOSUBSTATE_UNKNOWN,
1735 NULL, NULL, 0, RIL_PINSTATE_ENABLED_BLOCKED, RIL_PINSTATE_UNKNOWN },
John Wang309ac292009-07-30 14:53:23 -07001736 // SIM_NETWORK_PERSONALIZATION = 5
Wink Savillef6aa7c12009-04-30 14:20:52 -07001737 { RIL_APPTYPE_SIM, RIL_APPSTATE_SUBSCRIPTION_PERSO, RIL_PERSOSUBSTATE_SIM_NETWORK,
1738 NULL, NULL, 0, RIL_PINSTATE_ENABLED_NOT_VERIFIED, RIL_PINSTATE_UNKNOWN }
1739 };
1740 RIL_CardState card_state;
1741 int num_apps;
1742
1743 int sim_status = getSIMStatus();
John Wang309ac292009-07-30 14:53:23 -07001744 if (sim_status == SIM_ABSENT) {
Wink Savillef6aa7c12009-04-30 14:20:52 -07001745 card_state = RIL_CARDSTATE_ABSENT;
1746 num_apps = 0;
1747 } else {
1748 card_state = RIL_CARDSTATE_PRESENT;
1749 num_apps = 1;
1750 }
1751
1752 // Allocate and initialize base card status.
Wink Saville2c1fb3a2011-03-19 13:42:45 -07001753 RIL_CardStatus_v6 *p_card_status = malloc(sizeof(RIL_CardStatus_v6));
Wink Savillef6aa7c12009-04-30 14:20:52 -07001754 p_card_status->card_state = card_state;
1755 p_card_status->universal_pin_state = RIL_PINSTATE_UNKNOWN;
1756 p_card_status->gsm_umts_subscription_app_index = RIL_CARD_MAX_APPS;
1757 p_card_status->cdma_subscription_app_index = RIL_CARD_MAX_APPS;
Wink Saville2c1fb3a2011-03-19 13:42:45 -07001758 p_card_status->ims_subscription_app_index = RIL_CARD_MAX_APPS;
Wink Savillef6aa7c12009-04-30 14:20:52 -07001759 p_card_status->num_applications = num_apps;
1760
1761 // Initialize application status
1762 int i;
1763 for (i = 0; i < RIL_CARD_MAX_APPS; i++) {
John Wang309ac292009-07-30 14:53:23 -07001764 p_card_status->applications[i] = app_status_array[SIM_ABSENT];
Wink Savillef6aa7c12009-04-30 14:20:52 -07001765 }
1766
1767 // Pickup the appropriate application status
1768 // that reflects sim_status for gsm.
1769 if (num_apps != 0) {
1770 // Only support one app, gsm
1771 p_card_status->num_applications = 1;
1772 p_card_status->gsm_umts_subscription_app_index = 0;
1773
1774 // Get the correct app status
1775 p_card_status->applications[0] = app_status_array[sim_status];
1776 }
1777
1778 *pp_card_status = p_card_status;
1779 return RIL_E_SUCCESS;
1780}
1781
1782/**
1783 * Free the card status returned by getCardStatus
1784 */
Wink Saville2c1fb3a2011-03-19 13:42:45 -07001785static void freeCardStatus(RIL_CardStatus_v6 *p_card_status) {
Wink Savillef6aa7c12009-04-30 14:20:52 -07001786 free(p_card_status);
1787}
1788
1789/**
The Android Open Source Project00f06fc2009-03-03 19:32:15 -08001790 * SIM ready means any commands that access the SIM will work, including:
1791 * AT+CPIN, AT+CSMS, AT+CNMI, AT+CRSM
1792 * (all SMS-related commands)
1793 */
1794
1795static void pollSIMState (void *param)
1796{
1797 ATResponse *p_response;
1798 int ret;
1799
1800 if (sState != RADIO_STATE_SIM_NOT_READY) {
1801 // no longer valid to poll
1802 return;
1803 }
1804
1805 switch(getSIMStatus()) {
John Wang309ac292009-07-30 14:53:23 -07001806 case SIM_ABSENT:
1807 case SIM_PIN:
1808 case SIM_PUK:
1809 case SIM_NETWORK_PERSONALIZATION:
The Android Open Source Project00f06fc2009-03-03 19:32:15 -08001810 default:
1811 setRadioState(RADIO_STATE_SIM_LOCKED_OR_ABSENT);
1812 return;
1813
John Wang309ac292009-07-30 14:53:23 -07001814 case SIM_NOT_READY:
The Android Open Source Project00f06fc2009-03-03 19:32:15 -08001815 RIL_requestTimedCallback (pollSIMState, NULL, &TIMEVAL_SIMPOLL);
1816 return;
1817
John Wang309ac292009-07-30 14:53:23 -07001818 case SIM_READY:
The Android Open Source Project00f06fc2009-03-03 19:32:15 -08001819 setRadioState(RADIO_STATE_SIM_READY);
1820 return;
1821 }
1822}
1823
1824/** returns 1 if on, 0 if off, and -1 on error */
1825static int isRadioOn()
1826{
1827 ATResponse *p_response = NULL;
1828 int err;
1829 char *line;
1830 char ret;
1831
1832 err = at_send_command_singleline("AT+CFUN?", "+CFUN:", &p_response);
1833
1834 if (err < 0 || p_response->success == 0) {
1835 // assume radio is off
1836 goto error;
1837 }
1838
1839 line = p_response->p_intermediates->line;
1840
1841 err = at_tok_start(&line);
1842 if (err < 0) goto error;
1843
1844 err = at_tok_nextbool(&line, &ret);
1845 if (err < 0) goto error;
1846
1847 at_response_free(p_response);
1848
1849 return (int)ret;
1850
1851error:
1852
1853 at_response_free(p_response);
1854 return -1;
1855}
1856
1857/**
1858 * Initialize everything that can be configured while we're still in
1859 * AT+CFUN=0
1860 */
1861static void initializeCallback(void *param)
1862{
1863 ATResponse *p_response = NULL;
1864 int err;
1865
1866 setRadioState (RADIO_STATE_OFF);
1867
1868 at_handshake();
1869
1870 /* note: we don't check errors here. Everything important will
1871 be handled in onATTimeout and onATReaderClosed */
1872
1873 /* atchannel is tolerant of echo but it must */
1874 /* have verbose result codes */
1875 at_send_command("ATE0Q0V1", NULL);
1876
1877 /* No auto-answer */
1878 at_send_command("ATS0=0", NULL);
1879
1880 /* Extended errors */
1881 at_send_command("AT+CMEE=1", NULL);
1882
1883 /* Network registration events */
1884 err = at_send_command("AT+CREG=2", &p_response);
1885
1886 /* some handsets -- in tethered mode -- don't support CREG=2 */
1887 if (err < 0 || p_response->success == 0) {
1888 at_send_command("AT+CREG=1", NULL);
1889 }
1890
1891 at_response_free(p_response);
1892
1893 /* GPRS registration events */
1894 at_send_command("AT+CGREG=1", NULL);
1895
1896 /* Call Waiting notifications */
1897 at_send_command("AT+CCWA=1", NULL);
1898
1899 /* Alternating voice/data off */
1900 at_send_command("AT+CMOD=0", NULL);
1901
1902 /* Not muted */
1903 at_send_command("AT+CMUT=0", NULL);
1904
1905 /* +CSSU unsolicited supp service notifications */
1906 at_send_command("AT+CSSN=0,1", NULL);
1907
1908 /* no connected line identification */
1909 at_send_command("AT+COLP=0", NULL);
1910
1911 /* HEX character set */
1912 at_send_command("AT+CSCS=\"HEX\"", NULL);
1913
1914 /* USSD unsolicited */
1915 at_send_command("AT+CUSD=1", NULL);
1916
1917 /* Enable +CGEV GPRS event notifications, but don't buffer */
1918 at_send_command("AT+CGEREP=1,0", NULL);
1919
1920 /* SMS PDU mode */
1921 at_send_command("AT+CMGF=0", NULL);
1922
1923#ifdef USE_TI_COMMANDS
1924
1925 at_send_command("AT%CPI=3", NULL);
1926
1927 /* TI specific -- notifications when SMS is ready (currently ignored) */
1928 at_send_command("AT%CSTAT=1", NULL);
1929
1930#endif /* USE_TI_COMMANDS */
1931
1932
1933 /* assume radio is off on error */
1934 if (isRadioOn() > 0) {
1935 setRadioState (RADIO_STATE_SIM_NOT_READY);
1936 }
1937}
1938
1939static void waitForClose()
1940{
1941 pthread_mutex_lock(&s_state_mutex);
1942
1943 while (s_closed == 0) {
1944 pthread_cond_wait(&s_state_cond, &s_state_mutex);
1945 }
1946
1947 pthread_mutex_unlock(&s_state_mutex);
1948}
1949
1950/**
1951 * Called by atchannel when an unsolicited line appears
1952 * This is called on atchannel's reader thread. AT commands may
1953 * not be issued here
1954 */
1955static void onUnsolicited (const char *s, const char *sms_pdu)
1956{
1957 char *line = NULL;
1958 int err;
1959
1960 /* Ignore unsolicited responses until we're initialized.
1961 * This is OK because the RIL library will poll for initial state
1962 */
1963 if (sState == RADIO_STATE_UNAVAILABLE) {
1964 return;
1965 }
1966
1967 if (strStartsWith(s, "%CTZV:")) {
1968 /* TI specific -- NITZ time */
1969 char *response;
1970
1971 line = strdup(s);
1972 at_tok_start(&line);
1973
1974 err = at_tok_nextstr(&line, &response);
1975
1976 if (err != 0) {
1977 LOGE("invalid NITZ line %s\n", s);
1978 } else {
1979 RIL_onUnsolicitedResponse (
1980 RIL_UNSOL_NITZ_TIME_RECEIVED,
1981 response, strlen(response));
1982 }
1983 } else if (strStartsWith(s,"+CRING:")
1984 || strStartsWith(s,"RING")
1985 || strStartsWith(s,"NO CARRIER")
1986 || strStartsWith(s,"+CCWA")
1987 ) {
1988 RIL_onUnsolicitedResponse (
1989 RIL_UNSOL_RESPONSE_CALL_STATE_CHANGED,
1990 NULL, 0);
1991#ifdef WORKAROUND_FAKE_CGEV
Wink Savillef4c4d362009-04-02 01:37:03 -07001992 RIL_requestTimedCallback (onDataCallListChanged, NULL, NULL); //TODO use new function
The Android Open Source Project00f06fc2009-03-03 19:32:15 -08001993#endif /* WORKAROUND_FAKE_CGEV */
1994 } else if (strStartsWith(s,"+CREG:")
1995 || strStartsWith(s,"+CGREG:")
1996 ) {
1997 RIL_onUnsolicitedResponse (
Wink Saville2c1fb3a2011-03-19 13:42:45 -07001998 RIL_UNSOL_RESPONSE_VOICE_NETWORK_STATE_CHANGED,
The Android Open Source Project00f06fc2009-03-03 19:32:15 -08001999 NULL, 0);
2000#ifdef WORKAROUND_FAKE_CGEV
Wink Saville7f856802009-06-09 10:23:37 -07002001 RIL_requestTimedCallback (onDataCallListChanged, NULL, NULL);
The Android Open Source Project00f06fc2009-03-03 19:32:15 -08002002#endif /* WORKAROUND_FAKE_CGEV */
2003 } else if (strStartsWith(s, "+CMT:")) {
2004 RIL_onUnsolicitedResponse (
2005 RIL_UNSOL_RESPONSE_NEW_SMS,
2006 sms_pdu, strlen(sms_pdu));
2007 } else if (strStartsWith(s, "+CDS:")) {
2008 RIL_onUnsolicitedResponse (
2009 RIL_UNSOL_RESPONSE_NEW_SMS_STATUS_REPORT,
2010 sms_pdu, strlen(sms_pdu));
2011 } else if (strStartsWith(s, "+CGEV:")) {
2012 /* Really, we can ignore NW CLASS and ME CLASS events here,
2013 * but right now we don't since extranous
Wink Savillef4c4d362009-04-02 01:37:03 -07002014 * RIL_UNSOL_DATA_CALL_LIST_CHANGED calls are tolerated
The Android Open Source Project00f06fc2009-03-03 19:32:15 -08002015 */
2016 /* can't issue AT commands here -- call on main thread */
Wink Savillef4c4d362009-04-02 01:37:03 -07002017 RIL_requestTimedCallback (onDataCallListChanged, NULL, NULL);
The Android Open Source Project00f06fc2009-03-03 19:32:15 -08002018#ifdef WORKAROUND_FAKE_CGEV
2019 } else if (strStartsWith(s, "+CME ERROR: 150")) {
Wink Savillef4c4d362009-04-02 01:37:03 -07002020 RIL_requestTimedCallback (onDataCallListChanged, NULL, NULL);
The Android Open Source Project00f06fc2009-03-03 19:32:15 -08002021#endif /* WORKAROUND_FAKE_CGEV */
2022 }
2023}
2024
2025/* Called on command or reader thread */
2026static void onATReaderClosed()
2027{
2028 LOGI("AT channel closed\n");
2029 at_close();
2030 s_closed = 1;
2031
2032 setRadioState (RADIO_STATE_UNAVAILABLE);
2033}
2034
2035/* Called on command thread */
2036static void onATTimeout()
2037{
2038 LOGI("AT channel timeout; closing\n");
2039 at_close();
2040
2041 s_closed = 1;
2042
2043 /* FIXME cause a radio reset here */
2044
2045 setRadioState (RADIO_STATE_UNAVAILABLE);
2046}
2047
2048static void usage(char *s)
2049{
2050#ifdef RIL_SHLIB
2051 fprintf(stderr, "reference-ril requires: -p <tcp port> or -d /dev/tty_device\n");
2052#else
2053 fprintf(stderr, "usage: %s [-p <tcp port>] [-d /dev/tty_device]\n", s);
2054 exit(-1);
2055#endif
2056}
2057
2058static void *
2059mainLoop(void *param)
2060{
2061 int fd;
2062 int ret;
2063
2064 AT_DUMP("== ", "entering mainLoop()", -1 );
2065 at_set_on_reader_closed(onATReaderClosed);
2066 at_set_on_timeout(onATTimeout);
2067
2068 for (;;) {
2069 fd = -1;
2070 while (fd < 0) {
2071 if (s_port > 0) {
2072 fd = socket_loopback_client(s_port, SOCK_STREAM);
2073 } else if (s_device_socket) {
The Android Open Source Projecte6e6fb22009-03-18 17:39:47 -07002074 if (!strcmp(s_device_path, "/dev/socket/qemud")) {
2075 /* Qemu-specific control socket */
2076 fd = socket_local_client( "qemud",
2077 ANDROID_SOCKET_NAMESPACE_RESERVED,
2078 SOCK_STREAM );
2079 if (fd >= 0 ) {
2080 char answer[2];
2081
2082 if ( write(fd, "gsm", 3) != 3 ||
2083 read(fd, answer, 2) != 2 ||
2084 memcmp(answer, "OK", 2) != 0)
2085 {
2086 close(fd);
2087 fd = -1;
2088 }
2089 }
2090 }
2091 else
2092 fd = socket_local_client( s_device_path,
2093 ANDROID_SOCKET_NAMESPACE_FILESYSTEM,
2094 SOCK_STREAM );
The Android Open Source Project00f06fc2009-03-03 19:32:15 -08002095 } else if (s_device_path != NULL) {
2096 fd = open (s_device_path, O_RDWR);
2097 if ( fd >= 0 && !memcmp( s_device_path, "/dev/ttyS", 9 ) ) {
2098 /* disable echo on serial ports */
2099 struct termios ios;
2100 tcgetattr( fd, &ios );
2101 ios.c_lflag = 0; /* disable ECHO, ICANON, etc... */
2102 tcsetattr( fd, TCSANOW, &ios );
2103 }
2104 }
2105
2106 if (fd < 0) {
2107 perror ("opening AT interface. retrying...");
2108 sleep(10);
2109 /* never returns */
2110 }
2111 }
2112
2113 s_closed = 0;
2114 ret = at_open(fd, onUnsolicited);
2115
2116 if (ret < 0) {
2117 LOGE ("AT error %d on at_open\n", ret);
2118 return 0;
2119 }
2120
2121 RIL_requestTimedCallback(initializeCallback, NULL, &TIMEVAL_0);
2122
2123 // Give initializeCallback a chance to dispatched, since
2124 // we don't presently have a cancellation mechanism
2125 sleep(1);
2126
2127 waitForClose();
2128 LOGI("Re-opening after close");
2129 }
2130}
2131
2132#ifdef RIL_SHLIB
2133
2134pthread_t s_tid_mainloop;
2135
2136const RIL_RadioFunctions *RIL_Init(const struct RIL_Env *env, int argc, char **argv)
2137{
2138 int ret;
2139 int fd = -1;
2140 int opt;
2141 pthread_attr_t attr;
2142
2143 s_rilenv = env;
2144
2145 while ( -1 != (opt = getopt(argc, argv, "p:d:s:"))) {
2146 switch (opt) {
2147 case 'p':
2148 s_port = atoi(optarg);
2149 if (s_port == 0) {
2150 usage(argv[0]);
2151 return NULL;
2152 }
2153 LOGI("Opening loopback port %d\n", s_port);
2154 break;
2155
2156 case 'd':
2157 s_device_path = optarg;
2158 LOGI("Opening tty device %s\n", s_device_path);
2159 break;
2160
2161 case 's':
2162 s_device_path = optarg;
2163 s_device_socket = 1;
2164 LOGI("Opening socket %s\n", s_device_path);
2165 break;
2166
2167 default:
2168 usage(argv[0]);
2169 return NULL;
2170 }
2171 }
2172
2173 if (s_port < 0 && s_device_path == NULL) {
2174 usage(argv[0]);
2175 return NULL;
2176 }
2177
2178 pthread_attr_init (&attr);
2179 pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
2180 ret = pthread_create(&s_tid_mainloop, &attr, mainLoop, NULL);
2181
2182 return &s_callbacks;
2183}
2184#else /* RIL_SHLIB */
2185int main (int argc, char **argv)
2186{
2187 int ret;
2188 int fd = -1;
2189 int opt;
2190
2191 while ( -1 != (opt = getopt(argc, argv, "p:d:"))) {
2192 switch (opt) {
2193 case 'p':
2194 s_port = atoi(optarg);
2195 if (s_port == 0) {
2196 usage(argv[0]);
2197 }
2198 LOGI("Opening loopback port %d\n", s_port);
2199 break;
2200
2201 case 'd':
2202 s_device_path = optarg;
2203 LOGI("Opening tty device %s\n", s_device_path);
2204 break;
2205
2206 case 's':
2207 s_device_path = optarg;
2208 s_device_socket = 1;
2209 LOGI("Opening socket %s\n", s_device_path);
2210 break;
2211
2212 default:
2213 usage(argv[0]);
2214 }
2215 }
2216
2217 if (s_port < 0 && s_device_path == NULL) {
2218 usage(argv[0]);
2219 }
2220
2221 RIL_register(&s_callbacks);
2222
2223 mainLoop(NULL);
2224
2225 return 0;
2226}
2227
2228#endif /* RIL_SHLIB */