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