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