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