blob: 3700a22d4b1288f2129d10dc622b8e42cb1903f6 [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
18#include <telephony/ril.h>
19#include <stdio.h>
20#include <assert.h>
21#include <string.h>
22#include <errno.h>
23#include <unistd.h>
24#include <sys/types.h>
25#include <sys/stat.h>
26#include <fcntl.h>
27#include <pthread.h>
28#include <alloca.h>
29#include "atchannel.h"
30#include "at_tok.h"
31#include "misc.h"
32#include <getopt.h>
33#include <sys/socket.h>
34#include <cutils/sockets.h>
35#include <termios.h>
36
37#define LOG_TAG "RIL"
38#include <utils/Log.h>
39
40#define MAX_AT_RESPONSE 0x1000
41
Wink Savillef4c4d362009-04-02 01:37:03 -070042/* pathname returned from RIL_REQUEST_SETUP_DATA_CALL / RIL_REQUEST_SETUP_DEFAULT_PDP */
Robert Greenwaltf838ede2010-07-15 18:54:53 -070043#define PPP_TTY_PATH "eth0"
The Android Open Source Project00f06fc2009-03-03 19:32:15 -080044
45#ifdef USE_TI_COMMANDS
46
47// Enable a workaround
48// 1) Make incoming call, do not answer
49// 2) Hangup remote end
50// Expected: call should disappear from CLCC line
51// Actual: Call shows as "ACTIVE" before disappearing
52#define WORKAROUND_ERRONEOUS_ANSWER 1
53
54// Some varients of the TI stack do not support the +CGEV unsolicited
55// response. However, they seem to send an unsolicited +CME ERROR: 150
56#define WORKAROUND_FAKE_CGEV 1
57#endif
58
John Wang309ac292009-07-30 14:53:23 -070059typedef enum {
60 SIM_ABSENT = 0,
61 SIM_NOT_READY = 1,
62 SIM_READY = 2, /* SIM_READY means the radio state is RADIO_STATE_SIM_READY */
63 SIM_PIN = 3,
64 SIM_PUK = 4,
65 SIM_NETWORK_PERSONALIZATION = 5
66} SIM_Status;
67
The Android Open Source Project00f06fc2009-03-03 19:32:15 -080068static void onRequest (int request, void *data, size_t datalen, RIL_Token t);
69static RIL_RadioState currentState();
70static int onSupports (int requestCode);
71static void onCancel (RIL_Token t);
72static const char *getVersion();
73static int isRadioOn();
John Wang309ac292009-07-30 14:53:23 -070074static SIM_Status getSIMStatus();
Wink Savillef6aa7c12009-04-30 14:20:52 -070075static int getCardStatus(RIL_CardStatus **pp_card_status);
76static void freeCardStatus(RIL_CardStatus *p_card_status);
Wink Savillef4c4d362009-04-02 01:37:03 -070077static void onDataCallListChanged(void *param);
The Android Open Source Project00f06fc2009-03-03 19:32:15 -080078
79extern const char * requestToString(int request);
80
81/*** Static Variables ***/
82static const RIL_RadioFunctions s_callbacks = {
83 RIL_VERSION,
84 onRequest,
85 currentState,
86 onSupports,
87 onCancel,
88 getVersion
89};
90
91#ifdef RIL_SHLIB
92static const struct RIL_Env *s_rilenv;
93
94#define RIL_onRequestComplete(t, e, response, responselen) s_rilenv->OnRequestComplete(t,e, response, responselen)
95#define RIL_onUnsolicitedResponse(a,b,c) s_rilenv->OnUnsolicitedResponse(a,b,c)
96#define RIL_requestTimedCallback(a,b,c) s_rilenv->RequestTimedCallback(a,b,c)
97#endif
98
99static RIL_RadioState sState = RADIO_STATE_UNAVAILABLE;
100
101static pthread_mutex_t s_state_mutex = PTHREAD_MUTEX_INITIALIZER;
102static pthread_cond_t s_state_cond = PTHREAD_COND_INITIALIZER;
103
104static int s_port = -1;
105static const char * s_device_path = NULL;
106static int s_device_socket = 0;
107
108/* trigger change to this with s_state_cond */
109static int s_closed = 0;
110
111static int sFD; /* file desc of AT channel */
112static char sATBuffer[MAX_AT_RESPONSE+1];
113static char *sATBufferCur = NULL;
114
115static const struct timeval TIMEVAL_SIMPOLL = {1,0};
116static const struct timeval TIMEVAL_CALLSTATEPOLL = {0,500000};
117static const struct timeval TIMEVAL_0 = {0,0};
118
119#ifdef WORKAROUND_ERRONEOUS_ANSWER
120// Max number of times we'll try to repoll when we think
121// we have a AT+CLCC race condition
122#define REPOLL_CALLS_COUNT_MAX 4
123
124// Line index that was incoming or waiting at last poll, or -1 for none
125static int s_incomingOrWaitingLine = -1;
126// Number of times we've asked for a repoll of AT+CLCC
127static int s_repollCallsCount = 0;
128// Should we expect a call to be answered in the next CLCC?
129static int s_expectAnswer = 0;
130#endif /* WORKAROUND_ERRONEOUS_ANSWER */
131
132static void pollSIMState (void *param);
133static void setRadioState(RIL_RadioState newState);
134
135static int clccStateToRILState(int state, RIL_CallState *p_state)
136
137{
138 switch(state) {
139 case 0: *p_state = RIL_CALL_ACTIVE; return 0;
140 case 1: *p_state = RIL_CALL_HOLDING; return 0;
141 case 2: *p_state = RIL_CALL_DIALING; return 0;
142 case 3: *p_state = RIL_CALL_ALERTING; return 0;
143 case 4: *p_state = RIL_CALL_INCOMING; return 0;
144 case 5: *p_state = RIL_CALL_WAITING; return 0;
145 default: return -1;
146 }
147}
148
149/**
150 * Note: directly modified line and has *p_call point directly into
151 * modified line
152 */
Wink Saville3d54e742009-05-18 18:00:44 -0700153static int callFromCLCCLine(char *line, RIL_Call *p_call)
The Android Open Source Project00f06fc2009-03-03 19:32:15 -0800154{
155 //+CLCC: 1,0,2,0,0,\"+18005551212\",145
156 // index,isMT,state,mode,isMpty(,number,TOA)?
157
158 int err;
159 int state;
160 int mode;
161
162 err = at_tok_start(&line);
163 if (err < 0) goto error;
164
165 err = at_tok_nextint(&line, &(p_call->index));
166 if (err < 0) goto error;
167
168 err = at_tok_nextbool(&line, &(p_call->isMT));
169 if (err < 0) goto error;
170
171 err = at_tok_nextint(&line, &state);
172 if (err < 0) goto error;
173
174 err = clccStateToRILState(state, &(p_call->state));
175 if (err < 0) goto error;
176
177 err = at_tok_nextint(&line, &mode);
178 if (err < 0) goto error;
179
180 p_call->isVoice = (mode == 0);
181
182 err = at_tok_nextbool(&line, &(p_call->isMpty));
183 if (err < 0) goto error;
184
185 if (at_tok_hasmore(&line)) {
186 err = at_tok_nextstr(&line, &(p_call->number));
187
188 /* tolerate null here */
189 if (err < 0) return 0;
190
191 // Some lame implementations return strings
192 // like "NOT AVAILABLE" in the CLCC line
193 if (p_call->number != NULL
194 && 0 == strspn(p_call->number, "+0123456789")
195 ) {
196 p_call->number = NULL;
197 }
198
199 err = at_tok_nextint(&line, &p_call->toa);
200 if (err < 0) goto error;
201 }
202
Wink Saville74fa3882009-12-22 15:35:41 -0800203 p_call->uusInfo = NULL;
204
The Android Open Source Project00f06fc2009-03-03 19:32:15 -0800205 return 0;
206
207error:
208 LOGE("invalid CLCC line\n");
209 return -1;
210}
211
212
213/** do post-AT+CFUN=1 initialization */
214static void onRadioPowerOn()
215{
216#ifdef USE_TI_COMMANDS
217 /* Must be after CFUN=1 */
218 /* TI specific -- notifications for CPHS things such */
219 /* as CPHS message waiting indicator */
220
221 at_send_command("AT%CPHS=1", NULL);
222
223 /* TI specific -- enable NITZ unsol notifs */
224 at_send_command("AT%CTZV=1", NULL);
225#endif
226
227 pollSIMState(NULL);
228}
229
230/** do post- SIM ready initialization */
231static void onSIMReady()
232{
233 at_send_command_singleline("AT+CSMS=1", "+CSMS:", NULL);
234 /*
235 * Always send SMS messages directly to the TE
236 *
237 * mode = 1 // discard when link is reserved (link should never be
238 * reserved)
239 * mt = 2 // most messages routed to TE
240 * bm = 2 // new cell BM's routed to TE
241 * ds = 1 // Status reports routed to TE
242 * bfr = 1 // flush buffer
243 */
244 at_send_command("AT+CNMI=1,2,2,1,1", NULL);
245}
246
247static void requestRadioPower(void *data, size_t datalen, RIL_Token t)
248{
249 int onOff;
250
251 int err;
252 ATResponse *p_response = NULL;
253
254 assert (datalen >= sizeof(int *));
255 onOff = ((int *)data)[0];
256
257 if (onOff == 0 && sState != RADIO_STATE_OFF) {
258 err = at_send_command("AT+CFUN=0", &p_response);
259 if (err < 0 || p_response->success == 0) goto error;
260 setRadioState(RADIO_STATE_OFF);
261 } else if (onOff > 0 && sState == RADIO_STATE_OFF) {
262 err = at_send_command("AT+CFUN=1", &p_response);
263 if (err < 0|| p_response->success == 0) {
264 // Some stacks return an error when there is no SIM,
265 // but they really turn the RF portion on
266 // So, if we get an error, let's check to see if it
267 // turned on anyway
268
269 if (isRadioOn() != 1) {
270 goto error;
271 }
272 }
273 setRadioState(RADIO_STATE_SIM_NOT_READY);
274 }
275
276 at_response_free(p_response);
277 RIL_onRequestComplete(t, RIL_E_SUCCESS, NULL, 0);
278 return;
279error:
280 at_response_free(p_response);
281 RIL_onRequestComplete(t, RIL_E_GENERIC_FAILURE, NULL, 0);
282}
283
Wink Savillef4c4d362009-04-02 01:37:03 -0700284static void requestOrSendDataCallList(RIL_Token *t);
The Android Open Source Project00f06fc2009-03-03 19:32:15 -0800285
Wink Savillef4c4d362009-04-02 01:37:03 -0700286static void onDataCallListChanged(void *param)
The Android Open Source Project00f06fc2009-03-03 19:32:15 -0800287{
Wink Savillef4c4d362009-04-02 01:37:03 -0700288 requestOrSendDataCallList(NULL);
The Android Open Source Project00f06fc2009-03-03 19:32:15 -0800289}
290
Wink Savillef4c4d362009-04-02 01:37:03 -0700291static void requestDataCallList(void *data, size_t datalen, RIL_Token t)
The Android Open Source Project00f06fc2009-03-03 19:32:15 -0800292{
Wink Savillef4c4d362009-04-02 01:37:03 -0700293 requestOrSendDataCallList(&t);
The Android Open Source Project00f06fc2009-03-03 19:32:15 -0800294}
295
Wink Savillef4c4d362009-04-02 01:37:03 -0700296static void requestOrSendDataCallList(RIL_Token *t)
The Android Open Source Project00f06fc2009-03-03 19:32:15 -0800297{
298 ATResponse *p_response;
299 ATLine *p_cur;
300 int err;
301 int n = 0;
302 char *out;
303
304 err = at_send_command_multiline ("AT+CGACT?", "+CGACT:", &p_response);
305 if (err != 0 || p_response->success == 0) {
306 if (t != NULL)
307 RIL_onRequestComplete(*t, RIL_E_GENERIC_FAILURE, NULL, 0);
308 else
Wink Savillef4c4d362009-04-02 01:37:03 -0700309 RIL_onUnsolicitedResponse(RIL_UNSOL_DATA_CALL_LIST_CHANGED,
The Android Open Source Project00f06fc2009-03-03 19:32:15 -0800310 NULL, 0);
311 return;
312 }
313
314 for (p_cur = p_response->p_intermediates; p_cur != NULL;
315 p_cur = p_cur->p_next)
316 n++;
317
Wink Savillef4c4d362009-04-02 01:37:03 -0700318 RIL_Data_Call_Response *responses =
319 alloca(n * sizeof(RIL_Data_Call_Response));
The Android Open Source Project00f06fc2009-03-03 19:32:15 -0800320
321 int i;
322 for (i = 0; i < n; i++) {
323 responses[i].cid = -1;
324 responses[i].active = -1;
325 responses[i].type = "";
326 responses[i].apn = "";
327 responses[i].address = "";
328 }
329
Wink Savillef4c4d362009-04-02 01:37:03 -0700330 RIL_Data_Call_Response *response = responses;
The Android Open Source Project00f06fc2009-03-03 19:32:15 -0800331 for (p_cur = p_response->p_intermediates; p_cur != NULL;
332 p_cur = p_cur->p_next) {
333 char *line = p_cur->line;
334
335 err = at_tok_start(&line);
336 if (err < 0)
337 goto error;
338
339 err = at_tok_nextint(&line, &response->cid);
340 if (err < 0)
341 goto error;
342
343 err = at_tok_nextint(&line, &response->active);
344 if (err < 0)
345 goto error;
346
347 response++;
348 }
349
350 at_response_free(p_response);
351
352 err = at_send_command_multiline ("AT+CGDCONT?", "+CGDCONT:", &p_response);
353 if (err != 0 || p_response->success == 0) {
354 if (t != NULL)
355 RIL_onRequestComplete(*t, RIL_E_GENERIC_FAILURE, NULL, 0);
356 else
Wink Savillef4c4d362009-04-02 01:37:03 -0700357 RIL_onUnsolicitedResponse(RIL_UNSOL_DATA_CALL_LIST_CHANGED,
The Android Open Source Project00f06fc2009-03-03 19:32:15 -0800358 NULL, 0);
359 return;
360 }
361
362 for (p_cur = p_response->p_intermediates; p_cur != NULL;
363 p_cur = p_cur->p_next) {
364 char *line = p_cur->line;
365 int cid;
366 char *type;
367 char *apn;
368 char *address;
369
370
371 err = at_tok_start(&line);
372 if (err < 0)
373 goto error;
374
375 err = at_tok_nextint(&line, &cid);
376 if (err < 0)
377 goto error;
378
379 for (i = 0; i < n; i++) {
380 if (responses[i].cid == cid)
381 break;
382 }
383
384 if (i >= n) {
385 /* details for a context we didn't hear about in the last request */
386 continue;
387 }
388
389 err = at_tok_nextstr(&line, &out);
390 if (err < 0)
391 goto error;
392
393 responses[i].type = alloca(strlen(out) + 1);
394 strcpy(responses[i].type, out);
395
396 err = at_tok_nextstr(&line, &out);
397 if (err < 0)
398 goto error;
399
400 responses[i].apn = alloca(strlen(out) + 1);
401 strcpy(responses[i].apn, out);
402
403 err = at_tok_nextstr(&line, &out);
404 if (err < 0)
405 goto error;
406
407 responses[i].address = alloca(strlen(out) + 1);
408 strcpy(responses[i].address, out);
409 }
410
411 at_response_free(p_response);
412
413 if (t != NULL)
414 RIL_onRequestComplete(*t, RIL_E_SUCCESS, responses,
Wink Savillef4c4d362009-04-02 01:37:03 -0700415 n * sizeof(RIL_Data_Call_Response));
The Android Open Source Project00f06fc2009-03-03 19:32:15 -0800416 else
Wink Savillef4c4d362009-04-02 01:37:03 -0700417 RIL_onUnsolicitedResponse(RIL_UNSOL_DATA_CALL_LIST_CHANGED,
The Android Open Source Project00f06fc2009-03-03 19:32:15 -0800418 responses,
Wink Savillef4c4d362009-04-02 01:37:03 -0700419 n * sizeof(RIL_Data_Call_Response));
The Android Open Source Project00f06fc2009-03-03 19:32:15 -0800420
421 return;
422
423error:
424 if (t != NULL)
425 RIL_onRequestComplete(*t, RIL_E_GENERIC_FAILURE, NULL, 0);
426 else
Wink Savillef4c4d362009-04-02 01:37:03 -0700427 RIL_onUnsolicitedResponse(RIL_UNSOL_DATA_CALL_LIST_CHANGED,
The Android Open Source Project00f06fc2009-03-03 19:32:15 -0800428 NULL, 0);
429
430 at_response_free(p_response);
431}
432
433static void requestQueryNetworkSelectionMode(
434 void *data, size_t datalen, RIL_Token t)
435{
436 int err;
437 ATResponse *p_response = NULL;
438 int response = 0;
439 char *line;
440
441 err = at_send_command_singleline("AT+COPS?", "+COPS:", &p_response);
442
443 if (err < 0 || p_response->success == 0) {
444 goto error;
445 }
446
447 line = p_response->p_intermediates->line;
448
449 err = at_tok_start(&line);
450
451 if (err < 0) {
452 goto error;
453 }
454
455 err = at_tok_nextint(&line, &response);
456
457 if (err < 0) {
458 goto error;
459 }
460
461 RIL_onRequestComplete(t, RIL_E_SUCCESS, &response, sizeof(int));
462 at_response_free(p_response);
463 return;
464error:
465 at_response_free(p_response);
466 LOGE("requestQueryNetworkSelectionMode must never return error when radio is on");
467 RIL_onRequestComplete(t, RIL_E_GENERIC_FAILURE, NULL, 0);
468}
469
470static void sendCallStateChanged(void *param)
471{
472 RIL_onUnsolicitedResponse (
473 RIL_UNSOL_RESPONSE_CALL_STATE_CHANGED,
474 NULL, 0);
475}
476
477static void requestGetCurrentCalls(void *data, size_t datalen, RIL_Token t)
478{
479 int err;
480 ATResponse *p_response;
481 ATLine *p_cur;
482 int countCalls;
483 int countValidCalls;
Wink Saville3d54e742009-05-18 18:00:44 -0700484 RIL_Call *p_calls;
485 RIL_Call **pp_calls;
The Android Open Source Project00f06fc2009-03-03 19:32:15 -0800486 int i;
487 int needRepoll = 0;
488
489#ifdef WORKAROUND_ERRONEOUS_ANSWER
490 int prevIncomingOrWaitingLine;
491
492 prevIncomingOrWaitingLine = s_incomingOrWaitingLine;
493 s_incomingOrWaitingLine = -1;
494#endif /*WORKAROUND_ERRONEOUS_ANSWER*/
495
496 err = at_send_command_multiline ("AT+CLCC", "+CLCC:", &p_response);
497
498 if (err != 0 || p_response->success == 0) {
499 RIL_onRequestComplete(t, RIL_E_GENERIC_FAILURE, NULL, 0);
500 return;
501 }
502
503 /* count the calls */
504 for (countCalls = 0, p_cur = p_response->p_intermediates
505 ; p_cur != NULL
506 ; p_cur = p_cur->p_next
507 ) {
508 countCalls++;
509 }
510
511 /* yes, there's an array of pointers and then an array of structures */
512
Wink Saville3d54e742009-05-18 18:00:44 -0700513 pp_calls = (RIL_Call **)alloca(countCalls * sizeof(RIL_Call *));
514 p_calls = (RIL_Call *)alloca(countCalls * sizeof(RIL_Call));
515 memset (p_calls, 0, countCalls * sizeof(RIL_Call));
The Android Open Source Project00f06fc2009-03-03 19:32:15 -0800516
517 /* init the pointer array */
518 for(i = 0; i < countCalls ; i++) {
519 pp_calls[i] = &(p_calls[i]);
520 }
521
522 for (countValidCalls = 0, p_cur = p_response->p_intermediates
523 ; p_cur != NULL
524 ; p_cur = p_cur->p_next
525 ) {
526 err = callFromCLCCLine(p_cur->line, p_calls + countValidCalls);
527
528 if (err != 0) {
529 continue;
530 }
531
532#ifdef WORKAROUND_ERRONEOUS_ANSWER
533 if (p_calls[countValidCalls].state == RIL_CALL_INCOMING
534 || p_calls[countValidCalls].state == RIL_CALL_WAITING
535 ) {
536 s_incomingOrWaitingLine = p_calls[countValidCalls].index;
537 }
538#endif /*WORKAROUND_ERRONEOUS_ANSWER*/
539
540 if (p_calls[countValidCalls].state != RIL_CALL_ACTIVE
541 && p_calls[countValidCalls].state != RIL_CALL_HOLDING
542 ) {
543 needRepoll = 1;
544 }
545
546 countValidCalls++;
547 }
548
549#ifdef WORKAROUND_ERRONEOUS_ANSWER
550 // Basically:
551 // A call was incoming or waiting
552 // Now it's marked as active
553 // But we never answered it
554 //
555 // This is probably a bug, and the call will probably
556 // disappear from the call list in the next poll
557 if (prevIncomingOrWaitingLine >= 0
558 && s_incomingOrWaitingLine < 0
559 && s_expectAnswer == 0
560 ) {
561 for (i = 0; i < countValidCalls ; i++) {
562
563 if (p_calls[i].index == prevIncomingOrWaitingLine
564 && p_calls[i].state == RIL_CALL_ACTIVE
565 && s_repollCallsCount < REPOLL_CALLS_COUNT_MAX
566 ) {
567 LOGI(
568 "Hit WORKAROUND_ERRONOUS_ANSWER case."
569 " Repoll count: %d\n", s_repollCallsCount);
570 s_repollCallsCount++;
571 goto error;
572 }
573 }
574 }
575
576 s_expectAnswer = 0;
577 s_repollCallsCount = 0;
578#endif /*WORKAROUND_ERRONEOUS_ANSWER*/
579
Wink Saville3d54e742009-05-18 18:00:44 -0700580 RIL_onRequestComplete(t, RIL_E_SUCCESS, pp_calls,
581 countValidCalls * sizeof (RIL_Call *));
The Android Open Source Project00f06fc2009-03-03 19:32:15 -0800582
583 at_response_free(p_response);
584
585#ifdef POLL_CALL_STATE
586 if (countValidCalls) { // We don't seem to get a "NO CARRIER" message from
587 // smd, so we're forced to poll until the call ends.
588#else
589 if (needRepoll) {
590#endif
591 RIL_requestTimedCallback (sendCallStateChanged, NULL, &TIMEVAL_CALLSTATEPOLL);
592 }
593
594 return;
595error:
596 RIL_onRequestComplete(t, RIL_E_GENERIC_FAILURE, NULL, 0);
597 at_response_free(p_response);
598}
599
600static void requestDial(void *data, size_t datalen, RIL_Token t)
601{
602 RIL_Dial *p_dial;
603 char *cmd;
604 const char *clir;
605 int ret;
606
607 p_dial = (RIL_Dial *)data;
608
609 switch (p_dial->clir) {
610 case 1: clir = "I"; break; /*invocation*/
611 case 2: clir = "i"; break; /*suppression*/
612 default:
613 case 0: clir = ""; break; /*subscription default*/
614 }
615
616 asprintf(&cmd, "ATD%s%s;", p_dial->address, clir);
617
618 ret = at_send_command(cmd, NULL);
619
620 free(cmd);
621
622 /* success or failure is ignored by the upper layer here.
623 it will call GET_CURRENT_CALLS and determine success that way */
624 RIL_onRequestComplete(t, RIL_E_SUCCESS, NULL, 0);
625}
626
627static void requestWriteSmsToSim(void *data, size_t datalen, RIL_Token t)
628{
629 RIL_SMS_WriteArgs *p_args;
630 char *cmd;
631 int length;
632 int err;
633 ATResponse *p_response = NULL;
634
635 p_args = (RIL_SMS_WriteArgs *)data;
636
637 length = strlen(p_args->pdu)/2;
638 asprintf(&cmd, "AT+CMGW=%d,%d", length, p_args->status);
639
640 err = at_send_command_sms(cmd, p_args->pdu, "+CMGW:", &p_response);
641
642 if (err != 0 || p_response->success == 0) goto error;
643
644 RIL_onRequestComplete(t, RIL_E_SUCCESS, NULL, 0);
645 at_response_free(p_response);
646
647 return;
648error:
649 RIL_onRequestComplete(t, RIL_E_GENERIC_FAILURE, NULL, 0);
650 at_response_free(p_response);
651}
652
653static void requestHangup(void *data, size_t datalen, RIL_Token t)
654{
655 int *p_line;
656
657 int ret;
658 char *cmd;
659
660 p_line = (int *)data;
661
662 // 3GPP 22.030 6.5.5
663 // "Releases a specific active call X"
664 asprintf(&cmd, "AT+CHLD=1%d", p_line[0]);
665
666 ret = at_send_command(cmd, NULL);
667
668 free(cmd);
669
670 /* success or failure is ignored by the upper layer here.
671 it will call GET_CURRENT_CALLS and determine success that way */
672 RIL_onRequestComplete(t, RIL_E_SUCCESS, NULL, 0);
673}
674
675static void requestSignalStrength(void *data, size_t datalen, RIL_Token t)
676{
677 ATResponse *p_response = NULL;
678 int err;
679 int response[2];
680 char *line;
681
682 err = at_send_command_singleline("AT+CSQ", "+CSQ:", &p_response);
683
684 if (err < 0 || p_response->success == 0) {
685 RIL_onRequestComplete(t, RIL_E_GENERIC_FAILURE, NULL, 0);
686 goto error;
687 }
688
689 line = p_response->p_intermediates->line;
690
691 err = at_tok_start(&line);
692 if (err < 0) goto error;
693
694 err = at_tok_nextint(&line, &(response[0]));
695 if (err < 0) goto error;
696
697 err = at_tok_nextint(&line, &(response[1]));
698 if (err < 0) goto error;
699
700 RIL_onRequestComplete(t, RIL_E_SUCCESS, response, sizeof(response));
701
702 at_response_free(p_response);
703 return;
704
705error:
706 LOGE("requestSignalStrength must never return an error when radio is on");
707 RIL_onRequestComplete(t, RIL_E_GENERIC_FAILURE, NULL, 0);
708 at_response_free(p_response);
709}
710
711static void requestRegistrationState(int request, void *data,
712 size_t datalen, RIL_Token t)
713{
714 int err;
715 int response[4];
716 char * responseStr[4];
717 ATResponse *p_response = NULL;
718 const char *cmd;
719 const char *prefix;
720 char *line, *p;
721 int commas;
722 int skip;
723 int count = 3;
724
725
726 if (request == RIL_REQUEST_REGISTRATION_STATE) {
727 cmd = "AT+CREG?";
728 prefix = "+CREG:";
729 } else if (request == RIL_REQUEST_GPRS_REGISTRATION_STATE) {
730 cmd = "AT+CGREG?";
731 prefix = "+CGREG:";
732 } else {
733 assert(0);
734 goto error;
735 }
736
737 err = at_send_command_singleline(cmd, prefix, &p_response);
738
739 if (err != 0) goto error;
740
741 line = p_response->p_intermediates->line;
742
743 err = at_tok_start(&line);
744 if (err < 0) goto error;
745
746 /* Ok you have to be careful here
747 * The solicited version of the CREG response is
748 * +CREG: n, stat, [lac, cid]
749 * and the unsolicited version is
750 * +CREG: stat, [lac, cid]
751 * The <n> parameter is basically "is unsolicited creg on?"
752 * which it should always be
753 *
754 * Now we should normally get the solicited version here,
755 * but the unsolicited version could have snuck in
756 * so we have to handle both
757 *
758 * Also since the LAC and CID are only reported when registered,
759 * we can have 1, 2, 3, or 4 arguments here
760 *
761 * finally, a +CGREG: answer may have a fifth value that corresponds
762 * to the network type, as in;
763 *
764 * +CGREG: n, stat [,lac, cid [,networkType]]
765 */
766
767 /* count number of commas */
768 commas = 0;
769 for (p = line ; *p != '\0' ;p++) {
770 if (*p == ',') commas++;
771 }
772
773 switch (commas) {
774 case 0: /* +CREG: <stat> */
775 err = at_tok_nextint(&line, &response[0]);
776 if (err < 0) goto error;
777 response[1] = -1;
778 response[2] = -1;
779 break;
780
781 case 1: /* +CREG: <n>, <stat> */
782 err = at_tok_nextint(&line, &skip);
783 if (err < 0) goto error;
784 err = at_tok_nextint(&line, &response[0]);
785 if (err < 0) goto error;
786 response[1] = -1;
787 response[2] = -1;
788 if (err < 0) goto error;
789 break;
790
791 case 2: /* +CREG: <stat>, <lac>, <cid> */
792 err = at_tok_nextint(&line, &response[0]);
793 if (err < 0) goto error;
794 err = at_tok_nexthexint(&line, &response[1]);
795 if (err < 0) goto error;
796 err = at_tok_nexthexint(&line, &response[2]);
797 if (err < 0) goto error;
798 break;
799 case 3: /* +CREG: <n>, <stat>, <lac>, <cid> */
800 err = at_tok_nextint(&line, &skip);
801 if (err < 0) goto error;
802 err = at_tok_nextint(&line, &response[0]);
803 if (err < 0) goto error;
804 err = at_tok_nexthexint(&line, &response[1]);
805 if (err < 0) goto error;
806 err = at_tok_nexthexint(&line, &response[2]);
807 if (err < 0) goto error;
808 break;
809 /* special case for CGREG, there is a fourth parameter
810 * that is the network type (unknown/gprs/edge/umts)
811 */
812 case 4: /* +CGREG: <n>, <stat>, <lac>, <cid>, <networkType> */
813 err = at_tok_nextint(&line, &skip);
814 if (err < 0) goto error;
815 err = at_tok_nextint(&line, &response[0]);
816 if (err < 0) goto error;
817 err = at_tok_nexthexint(&line, &response[1]);
818 if (err < 0) goto error;
819 err = at_tok_nexthexint(&line, &response[2]);
820 if (err < 0) goto error;
821 err = at_tok_nexthexint(&line, &response[3]);
822 if (err < 0) goto error;
823 count = 4;
824 break;
825 default:
826 goto error;
827 }
828
829 asprintf(&responseStr[0], "%d", response[0]);
John Wang6f189a62009-06-30 13:12:53 -0700830 asprintf(&responseStr[1], "%x", response[1]);
831 asprintf(&responseStr[2], "%x", response[2]);
The Android Open Source Project00f06fc2009-03-03 19:32:15 -0800832
833 if (count > 3)
834 asprintf(&responseStr[3], "%d", response[3]);
835
836 RIL_onRequestComplete(t, RIL_E_SUCCESS, responseStr, count*sizeof(char*));
837 at_response_free(p_response);
838
839 return;
840error:
841 LOGE("requestRegistrationState must never return an error when radio is on");
842 RIL_onRequestComplete(t, RIL_E_GENERIC_FAILURE, NULL, 0);
843 at_response_free(p_response);
844}
845
846static void requestOperator(void *data, size_t datalen, RIL_Token t)
847{
848 int err;
849 int i;
850 int skip;
851 ATLine *p_cur;
852 char *response[3];
853
854 memset(response, 0, sizeof(response));
855
856 ATResponse *p_response = NULL;
857
858 err = at_send_command_multiline(
859 "AT+COPS=3,0;+COPS?;+COPS=3,1;+COPS?;+COPS=3,2;+COPS?",
860 "+COPS:", &p_response);
861
862 /* we expect 3 lines here:
863 * +COPS: 0,0,"T - Mobile"
864 * +COPS: 0,1,"TMO"
865 * +COPS: 0,2,"310170"
866 */
867
868 if (err != 0) goto error;
869
870 for (i = 0, p_cur = p_response->p_intermediates
871 ; p_cur != NULL
872 ; p_cur = p_cur->p_next, i++
873 ) {
874 char *line = p_cur->line;
875
876 err = at_tok_start(&line);
877 if (err < 0) goto error;
878
879 err = at_tok_nextint(&line, &skip);
880 if (err < 0) goto error;
881
882 // If we're unregistered, we may just get
883 // a "+COPS: 0" response
884 if (!at_tok_hasmore(&line)) {
885 response[i] = NULL;
886 continue;
887 }
888
889 err = at_tok_nextint(&line, &skip);
890 if (err < 0) goto error;
891
892 // a "+COPS: 0, n" response is also possible
893 if (!at_tok_hasmore(&line)) {
894 response[i] = NULL;
895 continue;
896 }
897
898 err = at_tok_nextstr(&line, &(response[i]));
899 if (err < 0) goto error;
900 }
901
902 if (i != 3) {
903 /* expect 3 lines exactly */
904 goto error;
905 }
906
907 RIL_onRequestComplete(t, RIL_E_SUCCESS, response, sizeof(response));
908 at_response_free(p_response);
909
910 return;
911error:
912 LOGE("requestOperator must not return error when radio is on");
913 RIL_onRequestComplete(t, RIL_E_GENERIC_FAILURE, NULL, 0);
914 at_response_free(p_response);
915}
916
917static void requestSendSMS(void *data, size_t datalen, RIL_Token t)
918{
919 int err;
920 const char *smsc;
921 const char *pdu;
922 int tpLayerLength;
923 char *cmd1, *cmd2;
924 RIL_SMS_Response response;
925 ATResponse *p_response = NULL;
926
927 smsc = ((const char **)data)[0];
928 pdu = ((const char **)data)[1];
929
930 tpLayerLength = strlen(pdu)/2;
931
932 // "NULL for default SMSC"
933 if (smsc == NULL) {
934 smsc= "00";
935 }
936
937 asprintf(&cmd1, "AT+CMGS=%d", tpLayerLength);
938 asprintf(&cmd2, "%s%s", smsc, pdu);
939
940 err = at_send_command_sms(cmd1, cmd2, "+CMGS:", &p_response);
941
942 if (err != 0 || p_response->success == 0) goto error;
943
944 memset(&response, 0, sizeof(response));
945
946 /* FIXME fill in messageRef and ackPDU */
947
948 RIL_onRequestComplete(t, RIL_E_SUCCESS, &response, sizeof(response));
949 at_response_free(p_response);
950
951 return;
952error:
953 RIL_onRequestComplete(t, RIL_E_GENERIC_FAILURE, NULL, 0);
954 at_response_free(p_response);
955}
956
Wink Savillef4c4d362009-04-02 01:37:03 -0700957static void requestSetupDataCall(void *data, size_t datalen, RIL_Token t)
The Android Open Source Project00f06fc2009-03-03 19:32:15 -0800958{
959 const char *apn;
960 char *cmd;
961 int err;
962 ATResponse *p_response = NULL;
963 char *response[2] = { "1", PPP_TTY_PATH };
964
Wink Savillef4c4d362009-04-02 01:37:03 -0700965 apn = ((const char **)data)[2];
The Android Open Source Project00f06fc2009-03-03 19:32:15 -0800966
967#ifdef USE_TI_COMMANDS
968 // Config for multislot class 10 (probably default anyway eh?)
969 err = at_send_command("AT%CPRIM=\"GMM\",\"CONFIG MULTISLOT_CLASS=<10>\"",
970 NULL);
971
972 err = at_send_command("AT%DATA=2,\"UART\",1,,\"SER\",\"UART\",0", NULL);
973#endif /* USE_TI_COMMANDS */
974
975 int fd, qmistatus;
976 size_t cur = 0;
977 size_t len;
978 ssize_t written, rlen;
979 char status[32] = {0};
980 int retry = 10;
Lorenzo Colitti4f81dcf2010-09-01 19:38:57 -0700981 const char *pdp_type;
The Android Open Source Project00f06fc2009-03-03 19:32:15 -0800982
983 LOGD("requesting data connection to APN '%s'", apn);
984
985 fd = open ("/dev/qmi", O_RDWR);
986 if (fd >= 0) { /* the device doesn't exist on the emulator */
987
Lorenzo Colitti4f81dcf2010-09-01 19:38:57 -0700988 LOGD("opened the qmi device\n");
989 asprintf(&cmd, "up:%s", apn);
990 len = strlen(cmd);
The Android Open Source Project00f06fc2009-03-03 19:32:15 -0800991
Lorenzo Colitti4f81dcf2010-09-01 19:38:57 -0700992 while (cur < len) {
993 do {
994 written = write (fd, cmd + cur, len - cur);
995 } while (written < 0 && errno == EINTR);
The Android Open Source Project00f06fc2009-03-03 19:32:15 -0800996
Lorenzo Colitti4f81dcf2010-09-01 19:38:57 -0700997 if (written < 0) {
The Android Open Source Project00f06fc2009-03-03 19:32:15 -0800998 LOGE("### ERROR writing to /dev/qmi");
999 close(fd);
1000 goto error;
1001 }
1002
1003 cur += written;
1004 }
1005
1006 // wait for interface to come online
1007
1008 do {
1009 sleep(1);
1010 do {
1011 rlen = read(fd, status, 31);
1012 } while (rlen < 0 && errno == EINTR);
1013
1014 if (rlen < 0) {
1015 LOGE("### ERROR reading from /dev/qmi");
1016 close(fd);
1017 goto error;
1018 } else {
1019 status[rlen] = '\0';
1020 LOGD("### status: %s", status);
1021 }
1022 } while (strncmp(status, "STATE=up", 8) && strcmp(status, "online") && --retry);
1023
1024 close(fd);
1025
1026 if (retry == 0) {
1027 LOGE("### Failed to get data connection up\n");
Lorenzo Colitti4f81dcf2010-09-01 19:38:57 -07001028 goto error;
1029 }
The Android Open Source Project00f06fc2009-03-03 19:32:15 -08001030
1031 qmistatus = system("netcfg rmnet0 dhcp");
1032
1033 LOGD("netcfg rmnet0 dhcp: status %d\n", qmistatus);
1034
Lorenzo Colitti4f81dcf2010-09-01 19:38:57 -07001035 if (qmistatus < 0) goto error;
The Android Open Source Project00f06fc2009-03-03 19:32:15 -08001036
Lorenzo Colitti4f81dcf2010-09-01 19:38:57 -07001037 } else {
The Android Open Source Project00f06fc2009-03-03 19:32:15 -08001038
Lorenzo Colitti4f81dcf2010-09-01 19:38:57 -07001039 if (datalen > 6 * sizeof(char *)) {
1040 pdp_type = ((const char **)data)[6];
1041 } else {
1042 pdp_type = "IP";
1043 }
The Android Open Source Project00f06fc2009-03-03 19:32:15 -08001044
Lorenzo Colitti4f81dcf2010-09-01 19:38:57 -07001045 asprintf(&cmd, "AT+CGDCONT=1,\"%s\",\"%s\",,0,0", apn, pdp_type);
1046 //FIXME check for error here
1047 err = at_send_command(cmd, NULL);
1048 free(cmd);
The Android Open Source Project00f06fc2009-03-03 19:32:15 -08001049
Lorenzo Colitti4f81dcf2010-09-01 19:38:57 -07001050 // Set required QoS params to default
1051 err = at_send_command("AT+CGQREQ=1", NULL);
The Android Open Source Project00f06fc2009-03-03 19:32:15 -08001052
Lorenzo Colitti4f81dcf2010-09-01 19:38:57 -07001053 // Set minimum QoS params to default
1054 err = at_send_command("AT+CGQMIN=1", NULL);
The Android Open Source Project00f06fc2009-03-03 19:32:15 -08001055
Lorenzo Colitti4f81dcf2010-09-01 19:38:57 -07001056 // packet-domain event reporting
1057 err = at_send_command("AT+CGEREP=1,0", NULL);
The Android Open Source Project00f06fc2009-03-03 19:32:15 -08001058
Lorenzo Colitti4f81dcf2010-09-01 19:38:57 -07001059 // Hangup anything that's happening there now
1060 err = at_send_command("AT+CGACT=1,0", NULL);
The Android Open Source Project00f06fc2009-03-03 19:32:15 -08001061
Lorenzo Colitti4f81dcf2010-09-01 19:38:57 -07001062 // Start data on PDP context 1
1063 err = at_send_command("ATD*99***1#", &p_response);
1064
1065 if (err < 0 || p_response->success == 0) {
1066 goto error;
1067 }
The Android Open Source Project00f06fc2009-03-03 19:32:15 -08001068 }
1069
1070 RIL_onRequestComplete(t, RIL_E_SUCCESS, response, sizeof(response));
1071 at_response_free(p_response);
1072
1073 return;
1074error:
1075 RIL_onRequestComplete(t, RIL_E_GENERIC_FAILURE, NULL, 0);
1076 at_response_free(p_response);
1077
1078}
1079
1080static void requestSMSAcknowledge(void *data, size_t datalen, RIL_Token t)
1081{
1082 int ackSuccess;
1083 int err;
1084
1085 ackSuccess = ((int *)data)[0];
1086
1087 if (ackSuccess == 1) {
1088 err = at_send_command("AT+CNMA=1", NULL);
1089 } else if (ackSuccess == 0) {
1090 err = at_send_command("AT+CNMA=2", NULL);
1091 } else {
1092 LOGE("unsupported arg to RIL_REQUEST_SMS_ACKNOWLEDGE\n");
1093 goto error;
1094 }
1095
1096 RIL_onRequestComplete(t, RIL_E_SUCCESS, NULL, 0);
1097error:
1098 RIL_onRequestComplete(t, RIL_E_GENERIC_FAILURE, NULL, 0);
1099
1100}
1101
1102static void requestSIM_IO(void *data, size_t datalen, RIL_Token t)
1103{
1104 ATResponse *p_response = NULL;
1105 RIL_SIM_IO_Response sr;
1106 int err;
1107 char *cmd = NULL;
1108 RIL_SIM_IO *p_args;
1109 char *line;
1110
1111 memset(&sr, 0, sizeof(sr));
1112
1113 p_args = (RIL_SIM_IO *)data;
1114
1115 /* FIXME handle pin2 */
1116
1117 if (p_args->data == NULL) {
1118 asprintf(&cmd, "AT+CRSM=%d,%d,%d,%d,%d",
1119 p_args->command, p_args->fileid,
1120 p_args->p1, p_args->p2, p_args->p3);
1121 } else {
1122 asprintf(&cmd, "AT+CRSM=%d,%d,%d,%d,%d,%s",
1123 p_args->command, p_args->fileid,
1124 p_args->p1, p_args->p2, p_args->p3, p_args->data);
1125 }
1126
1127 err = at_send_command_singleline(cmd, "+CRSM:", &p_response);
1128
1129 if (err < 0 || p_response->success == 0) {
1130 goto error;
1131 }
1132
1133 line = p_response->p_intermediates->line;
1134
1135 err = at_tok_start(&line);
1136 if (err < 0) goto error;
1137
1138 err = at_tok_nextint(&line, &(sr.sw1));
1139 if (err < 0) goto error;
1140
1141 err = at_tok_nextint(&line, &(sr.sw2));
1142 if (err < 0) goto error;
1143
1144 if (at_tok_hasmore(&line)) {
1145 err = at_tok_nextstr(&line, &(sr.simResponse));
1146 if (err < 0) goto error;
1147 }
1148
1149 RIL_onRequestComplete(t, RIL_E_SUCCESS, &sr, sizeof(sr));
1150 at_response_free(p_response);
1151 free(cmd);
1152
1153 return;
1154error:
1155 RIL_onRequestComplete(t, RIL_E_GENERIC_FAILURE, NULL, 0);
1156 at_response_free(p_response);
1157 free(cmd);
1158
1159}
1160
1161static void requestEnterSimPin(void* data, size_t datalen, RIL_Token t)
1162{
1163 ATResponse *p_response = NULL;
1164 int err;
1165 char* cmd = NULL;
1166 const char** strings = (const char**)data;;
1167
1168 if ( datalen == sizeof(char*) ) {
1169 asprintf(&cmd, "AT+CPIN=%s", strings[0]);
1170 } else if ( datalen == 2*sizeof(char*) ) {
1171 asprintf(&cmd, "AT+CPIN=%s,%s", strings[0], strings[1]);
1172 } else
1173 goto error;
1174
1175 err = at_send_command_singleline(cmd, "+CPIN:", &p_response);
1176 free(cmd);
1177
1178 if (err < 0 || p_response->success == 0) {
1179error:
1180 RIL_onRequestComplete(t, RIL_E_PASSWORD_INCORRECT, NULL, 0);
1181 } else {
1182 RIL_onRequestComplete(t, RIL_E_SUCCESS, NULL, 0);
1183 }
1184 at_response_free(p_response);
1185}
1186
1187
1188static void requestSendUSSD(void *data, size_t datalen, RIL_Token t)
1189{
1190 const char *ussdRequest;
1191
1192 ussdRequest = (char *)(data);
1193
1194
1195 RIL_onRequestComplete(t, RIL_E_REQUEST_NOT_SUPPORTED, NULL, 0);
1196
1197// @@@ TODO
1198
1199}
1200
1201
1202/*** Callback methods from the RIL library to us ***/
1203
1204/**
1205 * Call from RIL to us to make a RIL_REQUEST
1206 *
1207 * Must be completed with a call to RIL_onRequestComplete()
1208 *
1209 * RIL_onRequestComplete() may be called from any thread, before or after
1210 * this function returns.
1211 *
1212 * Will always be called from the same thread, so returning here implies
1213 * that the radio is ready to process another command (whether or not
1214 * the previous command has completed).
1215 */
1216static void
1217onRequest (int request, void *data, size_t datalen, RIL_Token t)
1218{
1219 ATResponse *p_response;
1220 int err;
1221
1222 LOGD("onRequest: %s", requestToString(request));
1223
1224 /* Ignore all requests except RIL_REQUEST_GET_SIM_STATUS
1225 * when RADIO_STATE_UNAVAILABLE.
1226 */
1227 if (sState == RADIO_STATE_UNAVAILABLE
1228 && request != RIL_REQUEST_GET_SIM_STATUS
1229 ) {
1230 RIL_onRequestComplete(t, RIL_E_RADIO_NOT_AVAILABLE, NULL, 0);
1231 return;
1232 }
1233
1234 /* Ignore all non-power requests when RADIO_STATE_OFF
1235 * (except RIL_REQUEST_GET_SIM_STATUS)
1236 */
1237 if (sState == RADIO_STATE_OFF
1238 && !(request == RIL_REQUEST_RADIO_POWER
1239 || request == RIL_REQUEST_GET_SIM_STATUS)
1240 ) {
1241 RIL_onRequestComplete(t, RIL_E_RADIO_NOT_AVAILABLE, NULL, 0);
1242 return;
1243 }
1244
1245 switch (request) {
1246 case RIL_REQUEST_GET_SIM_STATUS: {
Wink Savillef6aa7c12009-04-30 14:20:52 -07001247 RIL_CardStatus *p_card_status;
1248 char *p_buffer;
1249 int buffer_size;
The Android Open Source Project00f06fc2009-03-03 19:32:15 -08001250
Wink Savillef6aa7c12009-04-30 14:20:52 -07001251 int result = getCardStatus(&p_card_status);
1252 if (result == RIL_E_SUCCESS) {
1253 p_buffer = (char *)p_card_status;
1254 buffer_size = sizeof(*p_card_status);
1255 } else {
1256 p_buffer = NULL;
1257 buffer_size = 0;
1258 }
1259 RIL_onRequestComplete(t, result, p_buffer, buffer_size);
1260 freeCardStatus(p_card_status);
The Android Open Source Project00f06fc2009-03-03 19:32:15 -08001261 break;
1262 }
1263 case RIL_REQUEST_GET_CURRENT_CALLS:
1264 requestGetCurrentCalls(data, datalen, t);
1265 break;
1266 case RIL_REQUEST_DIAL:
1267 requestDial(data, datalen, t);
1268 break;
1269 case RIL_REQUEST_HANGUP:
1270 requestHangup(data, datalen, t);
1271 break;
1272 case RIL_REQUEST_HANGUP_WAITING_OR_BACKGROUND:
1273 // 3GPP 22.030 6.5.5
1274 // "Releases all held calls or sets User Determined User Busy
1275 // (UDUB) for a waiting call."
1276 at_send_command("AT+CHLD=0", NULL);
1277
1278 /* success or failure is ignored by the upper layer here.
1279 it will call GET_CURRENT_CALLS and determine success that way */
1280 RIL_onRequestComplete(t, RIL_E_SUCCESS, NULL, 0);
1281 break;
1282 case RIL_REQUEST_HANGUP_FOREGROUND_RESUME_BACKGROUND:
1283 // 3GPP 22.030 6.5.5
1284 // "Releases all active calls (if any exist) and accepts
1285 // the other (held or waiting) call."
1286 at_send_command("AT+CHLD=1", NULL);
1287
1288 /* success or failure is ignored by the upper layer here.
1289 it will call GET_CURRENT_CALLS and determine success that way */
1290 RIL_onRequestComplete(t, RIL_E_SUCCESS, NULL, 0);
1291 break;
1292 case RIL_REQUEST_SWITCH_WAITING_OR_HOLDING_AND_ACTIVE:
1293 // 3GPP 22.030 6.5.5
1294 // "Places all active calls (if any exist) on hold and accepts
1295 // the other (held or waiting) call."
1296 at_send_command("AT+CHLD=2", NULL);
1297
1298#ifdef WORKAROUND_ERRONEOUS_ANSWER
1299 s_expectAnswer = 1;
1300#endif /* WORKAROUND_ERRONEOUS_ANSWER */
1301
1302 /* success or failure is ignored by the upper layer here.
1303 it will call GET_CURRENT_CALLS and determine success that way */
1304 RIL_onRequestComplete(t, RIL_E_SUCCESS, NULL, 0);
1305 break;
1306 case RIL_REQUEST_ANSWER:
1307 at_send_command("ATA", NULL);
1308
1309#ifdef WORKAROUND_ERRONEOUS_ANSWER
1310 s_expectAnswer = 1;
1311#endif /* WORKAROUND_ERRONEOUS_ANSWER */
1312
1313 /* success or failure is ignored by the upper layer here.
1314 it will call GET_CURRENT_CALLS and determine success that way */
1315 RIL_onRequestComplete(t, RIL_E_SUCCESS, NULL, 0);
1316 break;
1317 case RIL_REQUEST_CONFERENCE:
1318 // 3GPP 22.030 6.5.5
1319 // "Adds a held call to the conversation"
1320 at_send_command("AT+CHLD=3", NULL);
1321
1322 /* success or failure is ignored by the upper layer here.
1323 it will call GET_CURRENT_CALLS and determine success that way */
1324 RIL_onRequestComplete(t, RIL_E_SUCCESS, NULL, 0);
1325 break;
1326 case RIL_REQUEST_UDUB:
1327 /* user determined user busy */
1328 /* sometimes used: ATH */
1329 at_send_command("ATH", NULL);
1330
1331 /* success or failure is ignored by the upper layer here.
1332 it will call GET_CURRENT_CALLS and determine success that way */
1333 RIL_onRequestComplete(t, RIL_E_SUCCESS, NULL, 0);
1334 break;
1335
1336 case RIL_REQUEST_SEPARATE_CONNECTION:
1337 {
1338 char cmd[12];
1339 int party = ((int*)data)[0];
1340
1341 // Make sure that party is in a valid range.
1342 // (Note: The Telephony middle layer imposes a range of 1 to 7.
1343 // It's sufficient for us to just make sure it's single digit.)
1344 if (party > 0 && party < 10) {
1345 sprintf(cmd, "AT+CHLD=2%d", party);
1346 at_send_command(cmd, NULL);
1347 RIL_onRequestComplete(t, RIL_E_SUCCESS, NULL, 0);
1348 } else {
1349 RIL_onRequestComplete(t, RIL_E_GENERIC_FAILURE, NULL, 0);
1350 }
1351 }
1352 break;
1353
1354 case RIL_REQUEST_SIGNAL_STRENGTH:
1355 requestSignalStrength(data, datalen, t);
1356 break;
1357 case RIL_REQUEST_REGISTRATION_STATE:
1358 case RIL_REQUEST_GPRS_REGISTRATION_STATE:
1359 requestRegistrationState(request, data, datalen, t);
1360 break;
1361 case RIL_REQUEST_OPERATOR:
1362 requestOperator(data, datalen, t);
1363 break;
1364 case RIL_REQUEST_RADIO_POWER:
1365 requestRadioPower(data, datalen, t);
1366 break;
1367 case RIL_REQUEST_DTMF: {
1368 char c = ((char *)data)[0];
1369 char *cmd;
1370 asprintf(&cmd, "AT+VTS=%c", (int)c);
1371 at_send_command(cmd, NULL);
1372 free(cmd);
1373 RIL_onRequestComplete(t, RIL_E_SUCCESS, NULL, 0);
1374 break;
1375 }
1376 case RIL_REQUEST_SEND_SMS:
1377 requestSendSMS(data, datalen, t);
1378 break;
Wink Savillef4c4d362009-04-02 01:37:03 -07001379 case RIL_REQUEST_SETUP_DATA_CALL:
1380 requestSetupDataCall(data, datalen, t);
The Android Open Source Project00f06fc2009-03-03 19:32:15 -08001381 break;
1382 case RIL_REQUEST_SMS_ACKNOWLEDGE:
1383 requestSMSAcknowledge(data, datalen, t);
1384 break;
1385
1386 case RIL_REQUEST_GET_IMSI:
1387 p_response = NULL;
1388 err = at_send_command_numeric("AT+CIMI", &p_response);
1389
1390 if (err < 0 || p_response->success == 0) {
1391 RIL_onRequestComplete(t, RIL_E_GENERIC_FAILURE, NULL, 0);
1392 } else {
1393 RIL_onRequestComplete(t, RIL_E_SUCCESS,
1394 p_response->p_intermediates->line, sizeof(char *));
1395 }
1396 at_response_free(p_response);
1397 break;
1398
1399 case RIL_REQUEST_GET_IMEI:
1400 p_response = NULL;
1401 err = at_send_command_numeric("AT+CGSN", &p_response);
1402
1403 if (err < 0 || p_response->success == 0) {
1404 RIL_onRequestComplete(t, RIL_E_GENERIC_FAILURE, NULL, 0);
1405 } else {
1406 RIL_onRequestComplete(t, RIL_E_SUCCESS,
1407 p_response->p_intermediates->line, sizeof(char *));
1408 }
1409 at_response_free(p_response);
1410 break;
1411
1412 case RIL_REQUEST_SIM_IO:
1413 requestSIM_IO(data,datalen,t);
1414 break;
1415
1416 case RIL_REQUEST_SEND_USSD:
1417 requestSendUSSD(data, datalen, t);
1418 break;
1419
1420 case RIL_REQUEST_CANCEL_USSD:
1421 p_response = NULL;
1422 err = at_send_command_numeric("AT+CUSD=2", &p_response);
1423
1424 if (err < 0 || p_response->success == 0) {
1425 RIL_onRequestComplete(t, RIL_E_GENERIC_FAILURE, NULL, 0);
1426 } else {
1427 RIL_onRequestComplete(t, RIL_E_SUCCESS,
1428 p_response->p_intermediates->line, sizeof(char *));
1429 }
1430 at_response_free(p_response);
1431 break;
1432
1433 case RIL_REQUEST_SET_NETWORK_SELECTION_AUTOMATIC:
1434 at_send_command("AT+COPS=0", NULL);
1435 break;
1436
Wink Savillef4c4d362009-04-02 01:37:03 -07001437 case RIL_REQUEST_DATA_CALL_LIST:
1438 requestDataCallList(data, datalen, t);
The Android Open Source Project00f06fc2009-03-03 19:32:15 -08001439 break;
1440
1441 case RIL_REQUEST_QUERY_NETWORK_SELECTION_MODE:
1442 requestQueryNetworkSelectionMode(data, datalen, t);
1443 break;
1444
1445 case RIL_REQUEST_OEM_HOOK_RAW:
1446 // echo back data
1447 RIL_onRequestComplete(t, RIL_E_SUCCESS, data, datalen);
1448 break;
1449
1450
1451 case RIL_REQUEST_OEM_HOOK_STRINGS: {
1452 int i;
1453 const char ** cur;
1454
1455 LOGD("got OEM_HOOK_STRINGS: 0x%8p %lu", data, (long)datalen);
1456
1457
1458 for (i = (datalen / sizeof (char *)), cur = (const char **)data ;
1459 i > 0 ; cur++, i --) {
1460 LOGD("> '%s'", *cur);
1461 }
1462
1463 // echo back strings
1464 RIL_onRequestComplete(t, RIL_E_SUCCESS, data, datalen);
1465 break;
1466 }
1467
1468 case RIL_REQUEST_WRITE_SMS_TO_SIM:
1469 requestWriteSmsToSim(data, datalen, t);
1470 break;
1471
1472 case RIL_REQUEST_DELETE_SMS_ON_SIM: {
1473 char * cmd;
1474 p_response = NULL;
1475 asprintf(&cmd, "AT+CMGD=%d", ((int *)data)[0]);
1476 err = at_send_command(cmd, &p_response);
1477 free(cmd);
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, NULL, 0);
1482 }
1483 at_response_free(p_response);
1484 break;
1485 }
1486
1487 case RIL_REQUEST_ENTER_SIM_PIN:
1488 case RIL_REQUEST_ENTER_SIM_PUK:
1489 case RIL_REQUEST_ENTER_SIM_PIN2:
1490 case RIL_REQUEST_ENTER_SIM_PUK2:
1491 case RIL_REQUEST_CHANGE_SIM_PIN:
1492 case RIL_REQUEST_CHANGE_SIM_PIN2:
1493 requestEnterSimPin(data, datalen, t);
1494 break;
1495
1496 default:
1497 RIL_onRequestComplete(t, RIL_E_REQUEST_NOT_SUPPORTED, NULL, 0);
1498 break;
1499 }
1500}
1501
1502/**
1503 * Synchronous call from the RIL to us to return current radio state.
1504 * RADIO_STATE_UNAVAILABLE should be the initial state.
1505 */
1506static RIL_RadioState
1507currentState()
1508{
1509 return sState;
1510}
1511/**
1512 * Call from RIL to us to find out whether a specific request code
1513 * is supported by this implementation.
1514 *
1515 * Return 1 for "supported" and 0 for "unsupported"
1516 */
1517
1518static int
1519onSupports (int requestCode)
1520{
1521 //@@@ todo
1522
1523 return 1;
1524}
1525
1526static void onCancel (RIL_Token t)
1527{
1528 //@@@todo
1529
1530}
1531
1532static const char * getVersion(void)
1533{
1534 return "android reference-ril 1.0";
1535}
1536
1537static void
1538setRadioState(RIL_RadioState newState)
1539{
1540 RIL_RadioState oldState;
1541
1542 pthread_mutex_lock(&s_state_mutex);
1543
1544 oldState = sState;
1545
1546 if (s_closed > 0) {
1547 // If we're closed, the only reasonable state is
1548 // RADIO_STATE_UNAVAILABLE
1549 // This is here because things on the main thread
1550 // may attempt to change the radio state after the closed
1551 // event happened in another thread
1552 newState = RADIO_STATE_UNAVAILABLE;
1553 }
1554
1555 if (sState != newState || s_closed > 0) {
1556 sState = newState;
1557
1558 pthread_cond_broadcast (&s_state_cond);
1559 }
1560
1561 pthread_mutex_unlock(&s_state_mutex);
1562
1563
1564 /* do these outside of the mutex */
1565 if (sState != oldState) {
1566 RIL_onUnsolicitedResponse (RIL_UNSOL_RESPONSE_RADIO_STATE_CHANGED,
1567 NULL, 0);
1568
1569 /* FIXME onSimReady() and onRadioPowerOn() cannot be called
1570 * from the AT reader thread
1571 * Currently, this doesn't happen, but if that changes then these
1572 * will need to be dispatched on the request thread
1573 */
1574 if (sState == RADIO_STATE_SIM_READY) {
1575 onSIMReady();
1576 } else if (sState == RADIO_STATE_SIM_NOT_READY) {
1577 onRadioPowerOn();
1578 }
1579 }
1580}
1581
John Wang309ac292009-07-30 14:53:23 -07001582/** Returns SIM_NOT_READY on error */
1583static SIM_Status
The Android Open Source Project00f06fc2009-03-03 19:32:15 -08001584getSIMStatus()
1585{
1586 ATResponse *p_response = NULL;
1587 int err;
1588 int ret;
1589 char *cpinLine;
1590 char *cpinResult;
1591
1592 if (sState == RADIO_STATE_OFF || sState == RADIO_STATE_UNAVAILABLE) {
John Wang309ac292009-07-30 14:53:23 -07001593 ret = SIM_NOT_READY;
The Android Open Source Project00f06fc2009-03-03 19:32:15 -08001594 goto done;
1595 }
1596
1597 err = at_send_command_singleline("AT+CPIN?", "+CPIN:", &p_response);
1598
1599 if (err != 0) {
John Wang309ac292009-07-30 14:53:23 -07001600 ret = SIM_NOT_READY;
The Android Open Source Project00f06fc2009-03-03 19:32:15 -08001601 goto done;
1602 }
1603
1604 switch (at_get_cme_error(p_response)) {
1605 case CME_SUCCESS:
1606 break;
1607
1608 case CME_SIM_NOT_INSERTED:
John Wang309ac292009-07-30 14:53:23 -07001609 ret = SIM_ABSENT;
The Android Open Source Project00f06fc2009-03-03 19:32:15 -08001610 goto done;
1611
1612 default:
John Wang309ac292009-07-30 14:53:23 -07001613 ret = SIM_NOT_READY;
The Android Open Source Project00f06fc2009-03-03 19:32:15 -08001614 goto done;
1615 }
1616
1617 /* CPIN? has succeeded, now look at the result */
1618
1619 cpinLine = p_response->p_intermediates->line;
1620 err = at_tok_start (&cpinLine);
1621
1622 if (err < 0) {
John Wang309ac292009-07-30 14:53:23 -07001623 ret = SIM_NOT_READY;
The Android Open Source Project00f06fc2009-03-03 19:32:15 -08001624 goto done;
1625 }
1626
1627 err = at_tok_nextstr(&cpinLine, &cpinResult);
1628
1629 if (err < 0) {
John Wang309ac292009-07-30 14:53:23 -07001630 ret = SIM_NOT_READY;
The Android Open Source Project00f06fc2009-03-03 19:32:15 -08001631 goto done;
1632 }
1633
1634 if (0 == strcmp (cpinResult, "SIM PIN")) {
John Wang309ac292009-07-30 14:53:23 -07001635 ret = SIM_PIN;
The Android Open Source Project00f06fc2009-03-03 19:32:15 -08001636 goto done;
1637 } else if (0 == strcmp (cpinResult, "SIM PUK")) {
John Wang309ac292009-07-30 14:53:23 -07001638 ret = SIM_PUK;
The Android Open Source Project00f06fc2009-03-03 19:32:15 -08001639 goto done;
1640 } else if (0 == strcmp (cpinResult, "PH-NET PIN")) {
John Wang309ac292009-07-30 14:53:23 -07001641 return SIM_NETWORK_PERSONALIZATION;
The Android Open Source Project00f06fc2009-03-03 19:32:15 -08001642 } else if (0 != strcmp (cpinResult, "READY")) {
1643 /* we're treating unsupported lock types as "sim absent" */
John Wang309ac292009-07-30 14:53:23 -07001644 ret = SIM_ABSENT;
The Android Open Source Project00f06fc2009-03-03 19:32:15 -08001645 goto done;
1646 }
1647
1648 at_response_free(p_response);
1649 p_response = NULL;
1650 cpinResult = NULL;
1651
John Wang309ac292009-07-30 14:53:23 -07001652 ret = SIM_READY;
The Android Open Source Project00f06fc2009-03-03 19:32:15 -08001653
1654done:
1655 at_response_free(p_response);
1656 return ret;
1657}
1658
1659
1660/**
Wink Savillef6aa7c12009-04-30 14:20:52 -07001661 * Get the current card status.
1662 *
1663 * This must be freed using freeCardStatus.
1664 * @return: On success returns RIL_E_SUCCESS
1665 */
1666static int getCardStatus(RIL_CardStatus **pp_card_status) {
1667 static RIL_AppStatus app_status_array[] = {
John Wang309ac292009-07-30 14:53:23 -07001668 // SIM_ABSENT = 0
Wink Savillef6aa7c12009-04-30 14:20:52 -07001669 { RIL_APPTYPE_UNKNOWN, RIL_APPSTATE_UNKNOWN, RIL_PERSOSUBSTATE_UNKNOWN,
1670 NULL, NULL, 0, RIL_PINSTATE_UNKNOWN, RIL_PINSTATE_UNKNOWN },
John Wang309ac292009-07-30 14:53:23 -07001671 // SIM_NOT_READY = 1
Wink Savillef6aa7c12009-04-30 14:20:52 -07001672 { RIL_APPTYPE_SIM, RIL_APPSTATE_DETECTED, RIL_PERSOSUBSTATE_UNKNOWN,
1673 NULL, NULL, 0, RIL_PINSTATE_UNKNOWN, RIL_PINSTATE_UNKNOWN },
John Wang309ac292009-07-30 14:53:23 -07001674 // SIM_READY = 2
Wink Savillef6aa7c12009-04-30 14:20:52 -07001675 { RIL_APPTYPE_SIM, RIL_APPSTATE_READY, RIL_PERSOSUBSTATE_READY,
1676 NULL, NULL, 0, RIL_PINSTATE_UNKNOWN, RIL_PINSTATE_UNKNOWN },
John Wang309ac292009-07-30 14:53:23 -07001677 // SIM_PIN = 3
Wink Savillef6aa7c12009-04-30 14:20:52 -07001678 { RIL_APPTYPE_SIM, RIL_APPSTATE_PIN, RIL_PERSOSUBSTATE_UNKNOWN,
1679 NULL, NULL, 0, RIL_PINSTATE_ENABLED_NOT_VERIFIED, RIL_PINSTATE_UNKNOWN },
John Wang309ac292009-07-30 14:53:23 -07001680 // SIM_PUK = 4
Wink Savillef6aa7c12009-04-30 14:20:52 -07001681 { RIL_APPTYPE_SIM, RIL_APPSTATE_PUK, RIL_PERSOSUBSTATE_UNKNOWN,
1682 NULL, NULL, 0, RIL_PINSTATE_ENABLED_BLOCKED, RIL_PINSTATE_UNKNOWN },
John Wang309ac292009-07-30 14:53:23 -07001683 // SIM_NETWORK_PERSONALIZATION = 5
Wink Savillef6aa7c12009-04-30 14:20:52 -07001684 { RIL_APPTYPE_SIM, RIL_APPSTATE_SUBSCRIPTION_PERSO, RIL_PERSOSUBSTATE_SIM_NETWORK,
1685 NULL, NULL, 0, RIL_PINSTATE_ENABLED_NOT_VERIFIED, RIL_PINSTATE_UNKNOWN }
1686 };
1687 RIL_CardState card_state;
1688 int num_apps;
1689
1690 int sim_status = getSIMStatus();
John Wang309ac292009-07-30 14:53:23 -07001691 if (sim_status == SIM_ABSENT) {
Wink Savillef6aa7c12009-04-30 14:20:52 -07001692 card_state = RIL_CARDSTATE_ABSENT;
1693 num_apps = 0;
1694 } else {
1695 card_state = RIL_CARDSTATE_PRESENT;
1696 num_apps = 1;
1697 }
1698
1699 // Allocate and initialize base card status.
1700 RIL_CardStatus *p_card_status = malloc(sizeof(RIL_CardStatus));
1701 p_card_status->card_state = card_state;
1702 p_card_status->universal_pin_state = RIL_PINSTATE_UNKNOWN;
1703 p_card_status->gsm_umts_subscription_app_index = RIL_CARD_MAX_APPS;
1704 p_card_status->cdma_subscription_app_index = RIL_CARD_MAX_APPS;
1705 p_card_status->num_applications = num_apps;
1706
1707 // Initialize application status
1708 int i;
1709 for (i = 0; i < RIL_CARD_MAX_APPS; i++) {
John Wang309ac292009-07-30 14:53:23 -07001710 p_card_status->applications[i] = app_status_array[SIM_ABSENT];
Wink Savillef6aa7c12009-04-30 14:20:52 -07001711 }
1712
1713 // Pickup the appropriate application status
1714 // that reflects sim_status for gsm.
1715 if (num_apps != 0) {
1716 // Only support one app, gsm
1717 p_card_status->num_applications = 1;
1718 p_card_status->gsm_umts_subscription_app_index = 0;
1719
1720 // Get the correct app status
1721 p_card_status->applications[0] = app_status_array[sim_status];
1722 }
1723
1724 *pp_card_status = p_card_status;
1725 return RIL_E_SUCCESS;
1726}
1727
1728/**
1729 * Free the card status returned by getCardStatus
1730 */
1731static void freeCardStatus(RIL_CardStatus *p_card_status) {
1732 free(p_card_status);
1733}
1734
1735/**
The Android Open Source Project00f06fc2009-03-03 19:32:15 -08001736 * SIM ready means any commands that access the SIM will work, including:
1737 * AT+CPIN, AT+CSMS, AT+CNMI, AT+CRSM
1738 * (all SMS-related commands)
1739 */
1740
1741static void pollSIMState (void *param)
1742{
1743 ATResponse *p_response;
1744 int ret;
1745
1746 if (sState != RADIO_STATE_SIM_NOT_READY) {
1747 // no longer valid to poll
1748 return;
1749 }
1750
1751 switch(getSIMStatus()) {
John Wang309ac292009-07-30 14:53:23 -07001752 case SIM_ABSENT:
1753 case SIM_PIN:
1754 case SIM_PUK:
1755 case SIM_NETWORK_PERSONALIZATION:
The Android Open Source Project00f06fc2009-03-03 19:32:15 -08001756 default:
1757 setRadioState(RADIO_STATE_SIM_LOCKED_OR_ABSENT);
1758 return;
1759
John Wang309ac292009-07-30 14:53:23 -07001760 case SIM_NOT_READY:
The Android Open Source Project00f06fc2009-03-03 19:32:15 -08001761 RIL_requestTimedCallback (pollSIMState, NULL, &TIMEVAL_SIMPOLL);
1762 return;
1763
John Wang309ac292009-07-30 14:53:23 -07001764 case SIM_READY:
The Android Open Source Project00f06fc2009-03-03 19:32:15 -08001765 setRadioState(RADIO_STATE_SIM_READY);
1766 return;
1767 }
1768}
1769
1770/** returns 1 if on, 0 if off, and -1 on error */
1771static int isRadioOn()
1772{
1773 ATResponse *p_response = NULL;
1774 int err;
1775 char *line;
1776 char ret;
1777
1778 err = at_send_command_singleline("AT+CFUN?", "+CFUN:", &p_response);
1779
1780 if (err < 0 || p_response->success == 0) {
1781 // assume radio is off
1782 goto error;
1783 }
1784
1785 line = p_response->p_intermediates->line;
1786
1787 err = at_tok_start(&line);
1788 if (err < 0) goto error;
1789
1790 err = at_tok_nextbool(&line, &ret);
1791 if (err < 0) goto error;
1792
1793 at_response_free(p_response);
1794
1795 return (int)ret;
1796
1797error:
1798
1799 at_response_free(p_response);
1800 return -1;
1801}
1802
1803/**
1804 * Initialize everything that can be configured while we're still in
1805 * AT+CFUN=0
1806 */
1807static void initializeCallback(void *param)
1808{
1809 ATResponse *p_response = NULL;
1810 int err;
1811
1812 setRadioState (RADIO_STATE_OFF);
1813
1814 at_handshake();
1815
1816 /* note: we don't check errors here. Everything important will
1817 be handled in onATTimeout and onATReaderClosed */
1818
1819 /* atchannel is tolerant of echo but it must */
1820 /* have verbose result codes */
1821 at_send_command("ATE0Q0V1", NULL);
1822
1823 /* No auto-answer */
1824 at_send_command("ATS0=0", NULL);
1825
1826 /* Extended errors */
1827 at_send_command("AT+CMEE=1", NULL);
1828
1829 /* Network registration events */
1830 err = at_send_command("AT+CREG=2", &p_response);
1831
1832 /* some handsets -- in tethered mode -- don't support CREG=2 */
1833 if (err < 0 || p_response->success == 0) {
1834 at_send_command("AT+CREG=1", NULL);
1835 }
1836
1837 at_response_free(p_response);
1838
1839 /* GPRS registration events */
1840 at_send_command("AT+CGREG=1", NULL);
1841
1842 /* Call Waiting notifications */
1843 at_send_command("AT+CCWA=1", NULL);
1844
1845 /* Alternating voice/data off */
1846 at_send_command("AT+CMOD=0", NULL);
1847
1848 /* Not muted */
1849 at_send_command("AT+CMUT=0", NULL);
1850
1851 /* +CSSU unsolicited supp service notifications */
1852 at_send_command("AT+CSSN=0,1", NULL);
1853
1854 /* no connected line identification */
1855 at_send_command("AT+COLP=0", NULL);
1856
1857 /* HEX character set */
1858 at_send_command("AT+CSCS=\"HEX\"", NULL);
1859
1860 /* USSD unsolicited */
1861 at_send_command("AT+CUSD=1", NULL);
1862
1863 /* Enable +CGEV GPRS event notifications, but don't buffer */
1864 at_send_command("AT+CGEREP=1,0", NULL);
1865
1866 /* SMS PDU mode */
1867 at_send_command("AT+CMGF=0", NULL);
1868
1869#ifdef USE_TI_COMMANDS
1870
1871 at_send_command("AT%CPI=3", NULL);
1872
1873 /* TI specific -- notifications when SMS is ready (currently ignored) */
1874 at_send_command("AT%CSTAT=1", NULL);
1875
1876#endif /* USE_TI_COMMANDS */
1877
1878
1879 /* assume radio is off on error */
1880 if (isRadioOn() > 0) {
1881 setRadioState (RADIO_STATE_SIM_NOT_READY);
1882 }
1883}
1884
1885static void waitForClose()
1886{
1887 pthread_mutex_lock(&s_state_mutex);
1888
1889 while (s_closed == 0) {
1890 pthread_cond_wait(&s_state_cond, &s_state_mutex);
1891 }
1892
1893 pthread_mutex_unlock(&s_state_mutex);
1894}
1895
1896/**
1897 * Called by atchannel when an unsolicited line appears
1898 * This is called on atchannel's reader thread. AT commands may
1899 * not be issued here
1900 */
1901static void onUnsolicited (const char *s, const char *sms_pdu)
1902{
1903 char *line = NULL;
1904 int err;
1905
1906 /* Ignore unsolicited responses until we're initialized.
1907 * This is OK because the RIL library will poll for initial state
1908 */
1909 if (sState == RADIO_STATE_UNAVAILABLE) {
1910 return;
1911 }
1912
1913 if (strStartsWith(s, "%CTZV:")) {
1914 /* TI specific -- NITZ time */
1915 char *response;
1916
1917 line = strdup(s);
1918 at_tok_start(&line);
1919
1920 err = at_tok_nextstr(&line, &response);
1921
1922 if (err != 0) {
1923 LOGE("invalid NITZ line %s\n", s);
1924 } else {
1925 RIL_onUnsolicitedResponse (
1926 RIL_UNSOL_NITZ_TIME_RECEIVED,
1927 response, strlen(response));
1928 }
1929 } else if (strStartsWith(s,"+CRING:")
1930 || strStartsWith(s,"RING")
1931 || strStartsWith(s,"NO CARRIER")
1932 || strStartsWith(s,"+CCWA")
1933 ) {
1934 RIL_onUnsolicitedResponse (
1935 RIL_UNSOL_RESPONSE_CALL_STATE_CHANGED,
1936 NULL, 0);
1937#ifdef WORKAROUND_FAKE_CGEV
Wink Savillef4c4d362009-04-02 01:37:03 -07001938 RIL_requestTimedCallback (onDataCallListChanged, NULL, NULL); //TODO use new function
The Android Open Source Project00f06fc2009-03-03 19:32:15 -08001939#endif /* WORKAROUND_FAKE_CGEV */
1940 } else if (strStartsWith(s,"+CREG:")
1941 || strStartsWith(s,"+CGREG:")
1942 ) {
1943 RIL_onUnsolicitedResponse (
1944 RIL_UNSOL_RESPONSE_NETWORK_STATE_CHANGED,
1945 NULL, 0);
1946#ifdef WORKAROUND_FAKE_CGEV
Wink Saville7f856802009-06-09 10:23:37 -07001947 RIL_requestTimedCallback (onDataCallListChanged, NULL, NULL);
The Android Open Source Project00f06fc2009-03-03 19:32:15 -08001948#endif /* WORKAROUND_FAKE_CGEV */
1949 } else if (strStartsWith(s, "+CMT:")) {
1950 RIL_onUnsolicitedResponse (
1951 RIL_UNSOL_RESPONSE_NEW_SMS,
1952 sms_pdu, strlen(sms_pdu));
1953 } else if (strStartsWith(s, "+CDS:")) {
1954 RIL_onUnsolicitedResponse (
1955 RIL_UNSOL_RESPONSE_NEW_SMS_STATUS_REPORT,
1956 sms_pdu, strlen(sms_pdu));
1957 } else if (strStartsWith(s, "+CGEV:")) {
1958 /* Really, we can ignore NW CLASS and ME CLASS events here,
1959 * but right now we don't since extranous
Wink Savillef4c4d362009-04-02 01:37:03 -07001960 * RIL_UNSOL_DATA_CALL_LIST_CHANGED calls are tolerated
The Android Open Source Project00f06fc2009-03-03 19:32:15 -08001961 */
1962 /* can't issue AT commands here -- call on main thread */
Wink Savillef4c4d362009-04-02 01:37:03 -07001963 RIL_requestTimedCallback (onDataCallListChanged, NULL, NULL);
The Android Open Source Project00f06fc2009-03-03 19:32:15 -08001964#ifdef WORKAROUND_FAKE_CGEV
1965 } else if (strStartsWith(s, "+CME ERROR: 150")) {
Wink Savillef4c4d362009-04-02 01:37:03 -07001966 RIL_requestTimedCallback (onDataCallListChanged, NULL, NULL);
The Android Open Source Project00f06fc2009-03-03 19:32:15 -08001967#endif /* WORKAROUND_FAKE_CGEV */
1968 }
1969}
1970
1971/* Called on command or reader thread */
1972static void onATReaderClosed()
1973{
1974 LOGI("AT channel closed\n");
1975 at_close();
1976 s_closed = 1;
1977
1978 setRadioState (RADIO_STATE_UNAVAILABLE);
1979}
1980
1981/* Called on command thread */
1982static void onATTimeout()
1983{
1984 LOGI("AT channel timeout; closing\n");
1985 at_close();
1986
1987 s_closed = 1;
1988
1989 /* FIXME cause a radio reset here */
1990
1991 setRadioState (RADIO_STATE_UNAVAILABLE);
1992}
1993
1994static void usage(char *s)
1995{
1996#ifdef RIL_SHLIB
1997 fprintf(stderr, "reference-ril requires: -p <tcp port> or -d /dev/tty_device\n");
1998#else
1999 fprintf(stderr, "usage: %s [-p <tcp port>] [-d /dev/tty_device]\n", s);
2000 exit(-1);
2001#endif
2002}
2003
2004static void *
2005mainLoop(void *param)
2006{
2007 int fd;
2008 int ret;
2009
2010 AT_DUMP("== ", "entering mainLoop()", -1 );
2011 at_set_on_reader_closed(onATReaderClosed);
2012 at_set_on_timeout(onATTimeout);
2013
2014 for (;;) {
2015 fd = -1;
2016 while (fd < 0) {
2017 if (s_port > 0) {
2018 fd = socket_loopback_client(s_port, SOCK_STREAM);
2019 } else if (s_device_socket) {
The Android Open Source Projecte6e6fb22009-03-18 17:39:47 -07002020 if (!strcmp(s_device_path, "/dev/socket/qemud")) {
2021 /* Qemu-specific control socket */
2022 fd = socket_local_client( "qemud",
2023 ANDROID_SOCKET_NAMESPACE_RESERVED,
2024 SOCK_STREAM );
2025 if (fd >= 0 ) {
2026 char answer[2];
2027
2028 if ( write(fd, "gsm", 3) != 3 ||
2029 read(fd, answer, 2) != 2 ||
2030 memcmp(answer, "OK", 2) != 0)
2031 {
2032 close(fd);
2033 fd = -1;
2034 }
2035 }
2036 }
2037 else
2038 fd = socket_local_client( s_device_path,
2039 ANDROID_SOCKET_NAMESPACE_FILESYSTEM,
2040 SOCK_STREAM );
The Android Open Source Project00f06fc2009-03-03 19:32:15 -08002041 } else if (s_device_path != NULL) {
2042 fd = open (s_device_path, O_RDWR);
2043 if ( fd >= 0 && !memcmp( s_device_path, "/dev/ttyS", 9 ) ) {
2044 /* disable echo on serial ports */
2045 struct termios ios;
2046 tcgetattr( fd, &ios );
2047 ios.c_lflag = 0; /* disable ECHO, ICANON, etc... */
2048 tcsetattr( fd, TCSANOW, &ios );
2049 }
2050 }
2051
2052 if (fd < 0) {
2053 perror ("opening AT interface. retrying...");
2054 sleep(10);
2055 /* never returns */
2056 }
2057 }
2058
2059 s_closed = 0;
2060 ret = at_open(fd, onUnsolicited);
2061
2062 if (ret < 0) {
2063 LOGE ("AT error %d on at_open\n", ret);
2064 return 0;
2065 }
2066
2067 RIL_requestTimedCallback(initializeCallback, NULL, &TIMEVAL_0);
2068
2069 // Give initializeCallback a chance to dispatched, since
2070 // we don't presently have a cancellation mechanism
2071 sleep(1);
2072
2073 waitForClose();
2074 LOGI("Re-opening after close");
2075 }
2076}
2077
2078#ifdef RIL_SHLIB
2079
2080pthread_t s_tid_mainloop;
2081
2082const RIL_RadioFunctions *RIL_Init(const struct RIL_Env *env, int argc, char **argv)
2083{
2084 int ret;
2085 int fd = -1;
2086 int opt;
2087 pthread_attr_t attr;
2088
2089 s_rilenv = env;
2090
2091 while ( -1 != (opt = getopt(argc, argv, "p:d:s:"))) {
2092 switch (opt) {
2093 case 'p':
2094 s_port = atoi(optarg);
2095 if (s_port == 0) {
2096 usage(argv[0]);
2097 return NULL;
2098 }
2099 LOGI("Opening loopback port %d\n", s_port);
2100 break;
2101
2102 case 'd':
2103 s_device_path = optarg;
2104 LOGI("Opening tty device %s\n", s_device_path);
2105 break;
2106
2107 case 's':
2108 s_device_path = optarg;
2109 s_device_socket = 1;
2110 LOGI("Opening socket %s\n", s_device_path);
2111 break;
2112
2113 default:
2114 usage(argv[0]);
2115 return NULL;
2116 }
2117 }
2118
2119 if (s_port < 0 && s_device_path == NULL) {
2120 usage(argv[0]);
2121 return NULL;
2122 }
2123
2124 pthread_attr_init (&attr);
2125 pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
2126 ret = pthread_create(&s_tid_mainloop, &attr, mainLoop, NULL);
2127
2128 return &s_callbacks;
2129}
2130#else /* RIL_SHLIB */
2131int main (int argc, char **argv)
2132{
2133 int ret;
2134 int fd = -1;
2135 int opt;
2136
2137 while ( -1 != (opt = getopt(argc, argv, "p:d:"))) {
2138 switch (opt) {
2139 case 'p':
2140 s_port = atoi(optarg);
2141 if (s_port == 0) {
2142 usage(argv[0]);
2143 }
2144 LOGI("Opening loopback port %d\n", s_port);
2145 break;
2146
2147 case 'd':
2148 s_device_path = optarg;
2149 LOGI("Opening tty device %s\n", s_device_path);
2150 break;
2151
2152 case 's':
2153 s_device_path = optarg;
2154 s_device_socket = 1;
2155 LOGI("Opening socket %s\n", s_device_path);
2156 break;
2157
2158 default:
2159 usage(argv[0]);
2160 }
2161 }
2162
2163 if (s_port < 0 && s_device_path == NULL) {
2164 usage(argv[0]);
2165 }
2166
2167 RIL_register(&s_callbacks);
2168
2169 mainLoop(NULL);
2170
2171 return 0;
2172}
2173
2174#endif /* RIL_SHLIB */