1 /* //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
42 /* pathname returned from RIL_REQUEST_SETUP_DATA_CALL / RIL_REQUEST_SETUP_DEFAULT_PDP */
43 #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
59 typedef 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
68 static void onRequest (int request, void *data, size_t datalen, RIL_Token t);
69 static RIL_RadioState currentState();
70 static int onSupports (int requestCode);
71 static void onCancel (RIL_Token t);
72 static const char *getVersion();
73 static int isRadioOn();
74 static SIM_Status getSIMStatus();
75 static int getCardStatus(RIL_CardStatus **pp_card_status);
76 static void freeCardStatus(RIL_CardStatus *p_card_status);
77 static void onDataCallListChanged(void *param);
78
79 extern const char * requestToString(int request);
80
81 /*** Static Variables ***/
82 static const RIL_RadioFunctions s_callbacks = {
83 RIL_VERSION,
84 onRequest,
85 currentState,
86 onSupports,
87 onCancel,
88 getVersion
89 };
90
91 #ifdef RIL_SHLIB
92 static 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
99 static RIL_RadioState sState = RADIO_STATE_UNAVAILABLE;
100
101 static pthread_mutex_t s_state_mutex = PTHREAD_MUTEX_INITIALIZER;
102 static pthread_cond_t s_state_cond = PTHREAD_COND_INITIALIZER;
103
104 static int s_port = -1;
105 static const char * s_device_path = NULL;
106 static int s_device_socket = 0;
107
108 /* trigger change to this with s_state_cond */
109 static int s_closed = 0;
110
111 static int sFD; /* file desc of AT channel */
112 static char sATBuffer[MAX_AT_RESPONSE+1];
113 static char *sATBufferCur = NULL;
114
115 static const struct timeval TIMEVAL_SIMPOLL = {1,0};
116 static const struct timeval TIMEVAL_CALLSTATEPOLL = {0,500000};
117 static 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
125 static int s_incomingOrWaitingLine = -1;
126 // Number of times we've asked for a repoll of AT+CLCC
127 static int s_repollCallsCount = 0;
128 // Should we expect a call to be answered in the next CLCC?
129 static int s_expectAnswer = 0;
130 #endif /* WORKAROUND_ERRONEOUS_ANSWER */
131
132 static void pollSIMState (void *param);
133 static void setRadioState(RIL_RadioState newState);
134
clccStateToRILState(int state,RIL_CallState * p_state)135 static 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 */
callFromCLCCLine(char * line,RIL_Call * p_call)153 static int callFromCLCCLine(char *line, RIL_Call *p_call)
154 {
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
203 p_call->uusInfo = NULL;
204
205 return 0;
206
207 error:
208 LOGE("invalid CLCC line\n");
209 return -1;
210 }
211
212
213 /** do post-AT+CFUN=1 initialization */
onRadioPowerOn()214 static 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 */
onSIMReady()231 static 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
requestRadioPower(void * data,size_t datalen,RIL_Token t)247 static 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;
279 error:
280 at_response_free(p_response);
281 RIL_onRequestComplete(t, RIL_E_GENERIC_FAILURE, NULL, 0);
282 }
283
284 static void requestOrSendDataCallList(RIL_Token *t);
285
onDataCallListChanged(void * param)286 static void onDataCallListChanged(void *param)
287 {
288 requestOrSendDataCallList(NULL);
289 }
290
requestDataCallList(void * data,size_t datalen,RIL_Token t)291 static void requestDataCallList(void *data, size_t datalen, RIL_Token t)
292 {
293 requestOrSendDataCallList(&t);
294 }
295
requestOrSendDataCallList(RIL_Token * t)296 static void requestOrSendDataCallList(RIL_Token *t)
297 {
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
309 RIL_onUnsolicitedResponse(RIL_UNSOL_DATA_CALL_LIST_CHANGED,
310 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
318 RIL_Data_Call_Response *responses =
319 alloca(n * sizeof(RIL_Data_Call_Response));
320
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
330 RIL_Data_Call_Response *response = responses;
331 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
357 RIL_onUnsolicitedResponse(RIL_UNSOL_DATA_CALL_LIST_CHANGED,
358 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,
415 n * sizeof(RIL_Data_Call_Response));
416 else
417 RIL_onUnsolicitedResponse(RIL_UNSOL_DATA_CALL_LIST_CHANGED,
418 responses,
419 n * sizeof(RIL_Data_Call_Response));
420
421 return;
422
423 error:
424 if (t != NULL)
425 RIL_onRequestComplete(*t, RIL_E_GENERIC_FAILURE, NULL, 0);
426 else
427 RIL_onUnsolicitedResponse(RIL_UNSOL_DATA_CALL_LIST_CHANGED,
428 NULL, 0);
429
430 at_response_free(p_response);
431 }
432
requestQueryNetworkSelectionMode(void * data,size_t datalen,RIL_Token t)433 static 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;
464 error:
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
sendCallStateChanged(void * param)470 static void sendCallStateChanged(void *param)
471 {
472 RIL_onUnsolicitedResponse (
473 RIL_UNSOL_RESPONSE_CALL_STATE_CHANGED,
474 NULL, 0);
475 }
476
requestGetCurrentCalls(void * data,size_t datalen,RIL_Token t)477 static 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;
484 RIL_Call *p_calls;
485 RIL_Call **pp_calls;
486 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
513 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));
516
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
580 RIL_onRequestComplete(t, RIL_E_SUCCESS, pp_calls,
581 countValidCalls * sizeof (RIL_Call *));
582
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;
595 error:
596 RIL_onRequestComplete(t, RIL_E_GENERIC_FAILURE, NULL, 0);
597 at_response_free(p_response);
598 }
599
600 static 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
627 static 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;
648 error:
649 RIL_onRequestComplete(t, RIL_E_GENERIC_FAILURE, NULL, 0);
650 at_response_free(p_response);
651 }
652
653 static 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
675 static 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
705 error:
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
711 static 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]);
830 asprintf(&responseStr[1], "%x", response[1]);
831 asprintf(&responseStr[2], "%x", response[2]);
832
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;
840 error:
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
846 static 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;
911 error:
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
917 static 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;
952 error:
953 RIL_onRequestComplete(t, RIL_E_GENERIC_FAILURE, NULL, 0);
954 at_response_free(p_response);
955 }
956
957 static void requestSetupDataCall(void *data, size_t datalen, RIL_Token t)
958 {
959 const char *apn;
960 char *cmd;
961 int err;
962 ATResponse *p_response = NULL;
963 char *response[2] = { "1", PPP_TTY_PATH };
964
965 apn = ((const char **)data)[2];
966
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;
981
982 LOGD("requesting data connection to APN '%s'", apn);
983
984 fd = open ("/dev/qmi", O_RDWR);
985 if (fd >= 0) { /* the device doesn't exist on the emulator */
986
987 LOGD("opened the qmi device\n");
988 asprintf(&cmd, "up:%s", apn);
989 len = strlen(cmd);
990
991 while (cur < len) {
992 do {
993 written = write (fd, cmd + cur, len - cur);
994 } while (written < 0 && errno == EINTR);
995
996 if (written < 0) {
997 LOGE("### ERROR writing to /dev/qmi");
998 close(fd);
999 goto error;
1000 }
1001
1002 cur += written;
1003 }
1004
1005 // wait for interface to come online
1006
1007 do {
1008 sleep(1);
1009 do {
1010 rlen = read(fd, status, 31);
1011 } while (rlen < 0 && errno == EINTR);
1012
1013 if (rlen < 0) {
1014 LOGE("### ERROR reading from /dev/qmi");
1015 close(fd);
1016 goto error;
1017 } else {
1018 status[rlen] = '\0';
1019 LOGD("### status: %s", status);
1020 }
1021 } while (strncmp(status, "STATE=up", 8) && strcmp(status, "online") && --retry);
1022
1023 close(fd);
1024
1025 if (retry == 0) {
1026 LOGE("### Failed to get data connection up\n");
1027 goto error;
1028 }
1029
1030 qmistatus = system("netcfg rmnet0 dhcp");
1031
1032 LOGD("netcfg rmnet0 dhcp: status %d\n", qmistatus);
1033
1034 if (qmistatus < 0) goto error;
1035
1036 } else {
1037
1038 asprintf(&cmd, "AT+CGDCONT=1,\"IP\",\"%s\",,0,0", apn);
1039 //FIXME check for error here
1040 err = at_send_command(cmd, NULL);
1041 free(cmd);
1042
1043 // Set required QoS params to default
1044 err = at_send_command("AT+CGQREQ=1", NULL);
1045
1046 // Set minimum QoS params to default
1047 err = at_send_command("AT+CGQMIN=1", NULL);
1048
1049 // packet-domain event reporting
1050 err = at_send_command("AT+CGEREP=1,0", NULL);
1051
1052 // Hangup anything that's happening there now
1053 err = at_send_command("AT+CGACT=1,0", NULL);
1054
1055 // Start data on PDP context 1
1056 err = at_send_command("ATD*99***1#", &p_response);
1057
1058 if (err < 0 || p_response->success == 0) {
1059 goto error;
1060 }
1061 }
1062
1063 RIL_onRequestComplete(t, RIL_E_SUCCESS, response, sizeof(response));
1064 at_response_free(p_response);
1065
1066 return;
1067 error:
1068 RIL_onRequestComplete(t, RIL_E_GENERIC_FAILURE, NULL, 0);
1069 at_response_free(p_response);
1070
1071 }
1072
1073 static void requestSMSAcknowledge(void *data, size_t datalen, RIL_Token t)
1074 {
1075 int ackSuccess;
1076 int err;
1077
1078 ackSuccess = ((int *)data)[0];
1079
1080 if (ackSuccess == 1) {
1081 err = at_send_command("AT+CNMA=1", NULL);
1082 } else if (ackSuccess == 0) {
1083 err = at_send_command("AT+CNMA=2", NULL);
1084 } else {
1085 LOGE("unsupported arg to RIL_REQUEST_SMS_ACKNOWLEDGE\n");
1086 goto error;
1087 }
1088
1089 RIL_onRequestComplete(t, RIL_E_SUCCESS, NULL, 0);
1090 error:
1091 RIL_onRequestComplete(t, RIL_E_GENERIC_FAILURE, NULL, 0);
1092
1093 }
1094
1095 static void requestSIM_IO(void *data, size_t datalen, RIL_Token t)
1096 {
1097 ATResponse *p_response = NULL;
1098 RIL_SIM_IO_Response sr;
1099 int err;
1100 char *cmd = NULL;
1101 RIL_SIM_IO *p_args;
1102 char *line;
1103
1104 memset(&sr, 0, sizeof(sr));
1105
1106 p_args = (RIL_SIM_IO *)data;
1107
1108 /* FIXME handle pin2 */
1109
1110 if (p_args->data == NULL) {
1111 asprintf(&cmd, "AT+CRSM=%d,%d,%d,%d,%d",
1112 p_args->command, p_args->fileid,
1113 p_args->p1, p_args->p2, p_args->p3);
1114 } else {
1115 asprintf(&cmd, "AT+CRSM=%d,%d,%d,%d,%d,%s",
1116 p_args->command, p_args->fileid,
1117 p_args->p1, p_args->p2, p_args->p3, p_args->data);
1118 }
1119
1120 err = at_send_command_singleline(cmd, "+CRSM:", &p_response);
1121
1122 if (err < 0 || p_response->success == 0) {
1123 goto error;
1124 }
1125
1126 line = p_response->p_intermediates->line;
1127
1128 err = at_tok_start(&line);
1129 if (err < 0) goto error;
1130
1131 err = at_tok_nextint(&line, &(sr.sw1));
1132 if (err < 0) goto error;
1133
1134 err = at_tok_nextint(&line, &(sr.sw2));
1135 if (err < 0) goto error;
1136
1137 if (at_tok_hasmore(&line)) {
1138 err = at_tok_nextstr(&line, &(sr.simResponse));
1139 if (err < 0) goto error;
1140 }
1141
1142 RIL_onRequestComplete(t, RIL_E_SUCCESS, &sr, sizeof(sr));
1143 at_response_free(p_response);
1144 free(cmd);
1145
1146 return;
1147 error:
1148 RIL_onRequestComplete(t, RIL_E_GENERIC_FAILURE, NULL, 0);
1149 at_response_free(p_response);
1150 free(cmd);
1151
1152 }
1153
1154 static void requestEnterSimPin(void* data, size_t datalen, RIL_Token t)
1155 {
1156 ATResponse *p_response = NULL;
1157 int err;
1158 char* cmd = NULL;
1159 const char** strings = (const char**)data;;
1160
1161 if ( datalen == sizeof(char*) ) {
1162 asprintf(&cmd, "AT+CPIN=%s", strings[0]);
1163 } else if ( datalen == 2*sizeof(char*) ) {
1164 asprintf(&cmd, "AT+CPIN=%s,%s", strings[0], strings[1]);
1165 } else
1166 goto error;
1167
1168 err = at_send_command_singleline(cmd, "+CPIN:", &p_response);
1169 free(cmd);
1170
1171 if (err < 0 || p_response->success == 0) {
1172 error:
1173 RIL_onRequestComplete(t, RIL_E_PASSWORD_INCORRECT, NULL, 0);
1174 } else {
1175 RIL_onRequestComplete(t, RIL_E_SUCCESS, NULL, 0);
1176 }
1177 at_response_free(p_response);
1178 }
1179
1180
1181 static void requestSendUSSD(void *data, size_t datalen, RIL_Token t)
1182 {
1183 const char *ussdRequest;
1184
1185 ussdRequest = (char *)(data);
1186
1187
1188 RIL_onRequestComplete(t, RIL_E_REQUEST_NOT_SUPPORTED, NULL, 0);
1189
1190 // @@@ TODO
1191
1192 }
1193
1194
1195 /*** Callback methods from the RIL library to us ***/
1196
1197 /**
1198 * Call from RIL to us to make a RIL_REQUEST
1199 *
1200 * Must be completed with a call to RIL_onRequestComplete()
1201 *
1202 * RIL_onRequestComplete() may be called from any thread, before or after
1203 * this function returns.
1204 *
1205 * Will always be called from the same thread, so returning here implies
1206 * that the radio is ready to process another command (whether or not
1207 * the previous command has completed).
1208 */
1209 static void
1210 onRequest (int request, void *data, size_t datalen, RIL_Token t)
1211 {
1212 ATResponse *p_response;
1213 int err;
1214
1215 LOGD("onRequest: %s", requestToString(request));
1216
1217 /* Ignore all requests except RIL_REQUEST_GET_SIM_STATUS
1218 * when RADIO_STATE_UNAVAILABLE.
1219 */
1220 if (sState == RADIO_STATE_UNAVAILABLE
1221 && request != RIL_REQUEST_GET_SIM_STATUS
1222 ) {
1223 RIL_onRequestComplete(t, RIL_E_RADIO_NOT_AVAILABLE, NULL, 0);
1224 return;
1225 }
1226
1227 /* Ignore all non-power requests when RADIO_STATE_OFF
1228 * (except RIL_REQUEST_GET_SIM_STATUS)
1229 */
1230 if (sState == RADIO_STATE_OFF
1231 && !(request == RIL_REQUEST_RADIO_POWER
1232 || request == RIL_REQUEST_GET_SIM_STATUS)
1233 ) {
1234 RIL_onRequestComplete(t, RIL_E_RADIO_NOT_AVAILABLE, NULL, 0);
1235 return;
1236 }
1237
1238 switch (request) {
1239 case RIL_REQUEST_GET_SIM_STATUS: {
1240 RIL_CardStatus *p_card_status;
1241 char *p_buffer;
1242 int buffer_size;
1243
1244 int result = getCardStatus(&p_card_status);
1245 if (result == RIL_E_SUCCESS) {
1246 p_buffer = (char *)p_card_status;
1247 buffer_size = sizeof(*p_card_status);
1248 } else {
1249 p_buffer = NULL;
1250 buffer_size = 0;
1251 }
1252 RIL_onRequestComplete(t, result, p_buffer, buffer_size);
1253 freeCardStatus(p_card_status);
1254 break;
1255 }
1256 case RIL_REQUEST_GET_CURRENT_CALLS:
1257 requestGetCurrentCalls(data, datalen, t);
1258 break;
1259 case RIL_REQUEST_DIAL:
1260 requestDial(data, datalen, t);
1261 break;
1262 case RIL_REQUEST_HANGUP:
1263 requestHangup(data, datalen, t);
1264 break;
1265 case RIL_REQUEST_HANGUP_WAITING_OR_BACKGROUND:
1266 // 3GPP 22.030 6.5.5
1267 // "Releases all held calls or sets User Determined User Busy
1268 // (UDUB) for a waiting call."
1269 at_send_command("AT+CHLD=0", NULL);
1270
1271 /* success or failure is ignored by the upper layer here.
1272 it will call GET_CURRENT_CALLS and determine success that way */
1273 RIL_onRequestComplete(t, RIL_E_SUCCESS, NULL, 0);
1274 break;
1275 case RIL_REQUEST_HANGUP_FOREGROUND_RESUME_BACKGROUND:
1276 // 3GPP 22.030 6.5.5
1277 // "Releases all active calls (if any exist) and accepts
1278 // the other (held or waiting) call."
1279 at_send_command("AT+CHLD=1", NULL);
1280
1281 /* success or failure is ignored by the upper layer here.
1282 it will call GET_CURRENT_CALLS and determine success that way */
1283 RIL_onRequestComplete(t, RIL_E_SUCCESS, NULL, 0);
1284 break;
1285 case RIL_REQUEST_SWITCH_WAITING_OR_HOLDING_AND_ACTIVE:
1286 // 3GPP 22.030 6.5.5
1287 // "Places all active calls (if any exist) on hold and accepts
1288 // the other (held or waiting) call."
1289 at_send_command("AT+CHLD=2", 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_ANSWER:
1300 at_send_command("ATA", NULL);
1301
1302 #ifdef WORKAROUND_ERRONEOUS_ANSWER
1303 s_expectAnswer = 1;
1304 #endif /* WORKAROUND_ERRONEOUS_ANSWER */
1305
1306 /* success or failure is ignored by the upper layer here.
1307 it will call GET_CURRENT_CALLS and determine success that way */
1308 RIL_onRequestComplete(t, RIL_E_SUCCESS, NULL, 0);
1309 break;
1310 case RIL_REQUEST_CONFERENCE:
1311 // 3GPP 22.030 6.5.5
1312 // "Adds a held call to the conversation"
1313 at_send_command("AT+CHLD=3", NULL);
1314
1315 /* success or failure is ignored by the upper layer here.
1316 it will call GET_CURRENT_CALLS and determine success that way */
1317 RIL_onRequestComplete(t, RIL_E_SUCCESS, NULL, 0);
1318 break;
1319 case RIL_REQUEST_UDUB:
1320 /* user determined user busy */
1321 /* sometimes used: ATH */
1322 at_send_command("ATH", NULL);
1323
1324 /* success or failure is ignored by the upper layer here.
1325 it will call GET_CURRENT_CALLS and determine success that way */
1326 RIL_onRequestComplete(t, RIL_E_SUCCESS, NULL, 0);
1327 break;
1328
1329 case RIL_REQUEST_SEPARATE_CONNECTION:
1330 {
1331 char cmd[12];
1332 int party = ((int*)data)[0];
1333
1334 // Make sure that party is in a valid range.
1335 // (Note: The Telephony middle layer imposes a range of 1 to 7.
1336 // It's sufficient for us to just make sure it's single digit.)
1337 if (party > 0 && party < 10) {
1338 sprintf(cmd, "AT+CHLD=2%d", party);
1339 at_send_command(cmd, NULL);
1340 RIL_onRequestComplete(t, RIL_E_SUCCESS, NULL, 0);
1341 } else {
1342 RIL_onRequestComplete(t, RIL_E_GENERIC_FAILURE, NULL, 0);
1343 }
1344 }
1345 break;
1346
1347 case RIL_REQUEST_SIGNAL_STRENGTH:
1348 requestSignalStrength(data, datalen, t);
1349 break;
1350 case RIL_REQUEST_REGISTRATION_STATE:
1351 case RIL_REQUEST_GPRS_REGISTRATION_STATE:
1352 requestRegistrationState(request, data, datalen, t);
1353 break;
1354 case RIL_REQUEST_OPERATOR:
1355 requestOperator(data, datalen, t);
1356 break;
1357 case RIL_REQUEST_RADIO_POWER:
1358 requestRadioPower(data, datalen, t);
1359 break;
1360 case RIL_REQUEST_DTMF: {
1361 char c = ((char *)data)[0];
1362 char *cmd;
1363 asprintf(&cmd, "AT+VTS=%c", (int)c);
1364 at_send_command(cmd, NULL);
1365 free(cmd);
1366 RIL_onRequestComplete(t, RIL_E_SUCCESS, NULL, 0);
1367 break;
1368 }
1369 case RIL_REQUEST_SEND_SMS:
1370 requestSendSMS(data, datalen, t);
1371 break;
1372 case RIL_REQUEST_SETUP_DATA_CALL:
1373 requestSetupDataCall(data, datalen, t);
1374 break;
1375 case RIL_REQUEST_SMS_ACKNOWLEDGE:
1376 requestSMSAcknowledge(data, datalen, t);
1377 break;
1378
1379 case RIL_REQUEST_GET_IMSI:
1380 p_response = NULL;
1381 err = at_send_command_numeric("AT+CIMI", &p_response);
1382
1383 if (err < 0 || p_response->success == 0) {
1384 RIL_onRequestComplete(t, RIL_E_GENERIC_FAILURE, NULL, 0);
1385 } else {
1386 RIL_onRequestComplete(t, RIL_E_SUCCESS,
1387 p_response->p_intermediates->line, sizeof(char *));
1388 }
1389 at_response_free(p_response);
1390 break;
1391
1392 case RIL_REQUEST_GET_IMEI:
1393 p_response = NULL;
1394 err = at_send_command_numeric("AT+CGSN", &p_response);
1395
1396 if (err < 0 || p_response->success == 0) {
1397 RIL_onRequestComplete(t, RIL_E_GENERIC_FAILURE, NULL, 0);
1398 } else {
1399 RIL_onRequestComplete(t, RIL_E_SUCCESS,
1400 p_response->p_intermediates->line, sizeof(char *));
1401 }
1402 at_response_free(p_response);
1403 break;
1404
1405 case RIL_REQUEST_SIM_IO:
1406 requestSIM_IO(data,datalen,t);
1407 break;
1408
1409 case RIL_REQUEST_SEND_USSD:
1410 requestSendUSSD(data, datalen, t);
1411 break;
1412
1413 case RIL_REQUEST_CANCEL_USSD:
1414 p_response = NULL;
1415 err = at_send_command_numeric("AT+CUSD=2", &p_response);
1416
1417 if (err < 0 || p_response->success == 0) {
1418 RIL_onRequestComplete(t, RIL_E_GENERIC_FAILURE, NULL, 0);
1419 } else {
1420 RIL_onRequestComplete(t, RIL_E_SUCCESS,
1421 p_response->p_intermediates->line, sizeof(char *));
1422 }
1423 at_response_free(p_response);
1424 break;
1425
1426 case RIL_REQUEST_SET_NETWORK_SELECTION_AUTOMATIC:
1427 at_send_command("AT+COPS=0", NULL);
1428 break;
1429
1430 case RIL_REQUEST_DATA_CALL_LIST:
1431 requestDataCallList(data, datalen, t);
1432 break;
1433
1434 case RIL_REQUEST_QUERY_NETWORK_SELECTION_MODE:
1435 requestQueryNetworkSelectionMode(data, datalen, t);
1436 break;
1437
1438 case RIL_REQUEST_OEM_HOOK_RAW:
1439 // echo back data
1440 RIL_onRequestComplete(t, RIL_E_SUCCESS, data, datalen);
1441 break;
1442
1443
1444 case RIL_REQUEST_OEM_HOOK_STRINGS: {
1445 int i;
1446 const char ** cur;
1447
1448 LOGD("got OEM_HOOK_STRINGS: 0x%8p %lu", data, (long)datalen);
1449
1450
1451 for (i = (datalen / sizeof (char *)), cur = (const char **)data ;
1452 i > 0 ; cur++, i --) {
1453 LOGD("> '%s'", *cur);
1454 }
1455
1456 // echo back strings
1457 RIL_onRequestComplete(t, RIL_E_SUCCESS, data, datalen);
1458 break;
1459 }
1460
1461 case RIL_REQUEST_WRITE_SMS_TO_SIM:
1462 requestWriteSmsToSim(data, datalen, t);
1463 break;
1464
1465 case RIL_REQUEST_DELETE_SMS_ON_SIM: {
1466 char * cmd;
1467 p_response = NULL;
1468 asprintf(&cmd, "AT+CMGD=%d", ((int *)data)[0]);
1469 err = at_send_command(cmd, &p_response);
1470 free(cmd);
1471 if (err < 0 || p_response->success == 0) {
1472 RIL_onRequestComplete(t, RIL_E_GENERIC_FAILURE, NULL, 0);
1473 } else {
1474 RIL_onRequestComplete(t, RIL_E_SUCCESS, NULL, 0);
1475 }
1476 at_response_free(p_response);
1477 break;
1478 }
1479
1480 case RIL_REQUEST_ENTER_SIM_PIN:
1481 case RIL_REQUEST_ENTER_SIM_PUK:
1482 case RIL_REQUEST_ENTER_SIM_PIN2:
1483 case RIL_REQUEST_ENTER_SIM_PUK2:
1484 case RIL_REQUEST_CHANGE_SIM_PIN:
1485 case RIL_REQUEST_CHANGE_SIM_PIN2:
1486 requestEnterSimPin(data, datalen, t);
1487 break;
1488
1489 default:
1490 RIL_onRequestComplete(t, RIL_E_REQUEST_NOT_SUPPORTED, NULL, 0);
1491 break;
1492 }
1493 }
1494
1495 /**
1496 * Synchronous call from the RIL to us to return current radio state.
1497 * RADIO_STATE_UNAVAILABLE should be the initial state.
1498 */
1499 static RIL_RadioState
1500 currentState()
1501 {
1502 return sState;
1503 }
1504 /**
1505 * Call from RIL to us to find out whether a specific request code
1506 * is supported by this implementation.
1507 *
1508 * Return 1 for "supported" and 0 for "unsupported"
1509 */
1510
1511 static int
1512 onSupports (int requestCode)
1513 {
1514 //@@@ todo
1515
1516 return 1;
1517 }
1518
1519 static void onCancel (RIL_Token t)
1520 {
1521 //@@@todo
1522
1523 }
1524
1525 static const char * getVersion(void)
1526 {
1527 return "android reference-ril 1.0";
1528 }
1529
1530 static void
1531 setRadioState(RIL_RadioState newState)
1532 {
1533 RIL_RadioState oldState;
1534
1535 pthread_mutex_lock(&s_state_mutex);
1536
1537 oldState = sState;
1538
1539 if (s_closed > 0) {
1540 // If we're closed, the only reasonable state is
1541 // RADIO_STATE_UNAVAILABLE
1542 // This is here because things on the main thread
1543 // may attempt to change the radio state after the closed
1544 // event happened in another thread
1545 newState = RADIO_STATE_UNAVAILABLE;
1546 }
1547
1548 if (sState != newState || s_closed > 0) {
1549 sState = newState;
1550
1551 pthread_cond_broadcast (&s_state_cond);
1552 }
1553
1554 pthread_mutex_unlock(&s_state_mutex);
1555
1556
1557 /* do these outside of the mutex */
1558 if (sState != oldState) {
1559 RIL_onUnsolicitedResponse (RIL_UNSOL_RESPONSE_RADIO_STATE_CHANGED,
1560 NULL, 0);
1561
1562 /* FIXME onSimReady() and onRadioPowerOn() cannot be called
1563 * from the AT reader thread
1564 * Currently, this doesn't happen, but if that changes then these
1565 * will need to be dispatched on the request thread
1566 */
1567 if (sState == RADIO_STATE_SIM_READY) {
1568 onSIMReady();
1569 } else if (sState == RADIO_STATE_SIM_NOT_READY) {
1570 onRadioPowerOn();
1571 }
1572 }
1573 }
1574
1575 /** Returns SIM_NOT_READY on error */
1576 static SIM_Status
1577 getSIMStatus()
1578 {
1579 ATResponse *p_response = NULL;
1580 int err;
1581 int ret;
1582 char *cpinLine;
1583 char *cpinResult;
1584
1585 if (sState == RADIO_STATE_OFF || sState == RADIO_STATE_UNAVAILABLE) {
1586 ret = SIM_NOT_READY;
1587 goto done;
1588 }
1589
1590 err = at_send_command_singleline("AT+CPIN?", "+CPIN:", &p_response);
1591
1592 if (err != 0) {
1593 ret = SIM_NOT_READY;
1594 goto done;
1595 }
1596
1597 switch (at_get_cme_error(p_response)) {
1598 case CME_SUCCESS:
1599 break;
1600
1601 case CME_SIM_NOT_INSERTED:
1602 ret = SIM_ABSENT;
1603 goto done;
1604
1605 default:
1606 ret = SIM_NOT_READY;
1607 goto done;
1608 }
1609
1610 /* CPIN? has succeeded, now look at the result */
1611
1612 cpinLine = p_response->p_intermediates->line;
1613 err = at_tok_start (&cpinLine);
1614
1615 if (err < 0) {
1616 ret = SIM_NOT_READY;
1617 goto done;
1618 }
1619
1620 err = at_tok_nextstr(&cpinLine, &cpinResult);
1621
1622 if (err < 0) {
1623 ret = SIM_NOT_READY;
1624 goto done;
1625 }
1626
1627 if (0 == strcmp (cpinResult, "SIM PIN")) {
1628 ret = SIM_PIN;
1629 goto done;
1630 } else if (0 == strcmp (cpinResult, "SIM PUK")) {
1631 ret = SIM_PUK;
1632 goto done;
1633 } else if (0 == strcmp (cpinResult, "PH-NET PIN")) {
1634 return SIM_NETWORK_PERSONALIZATION;
1635 } else if (0 != strcmp (cpinResult, "READY")) {
1636 /* we're treating unsupported lock types as "sim absent" */
1637 ret = SIM_ABSENT;
1638 goto done;
1639 }
1640
1641 at_response_free(p_response);
1642 p_response = NULL;
1643 cpinResult = NULL;
1644
1645 ret = SIM_READY;
1646
1647 done:
1648 at_response_free(p_response);
1649 return ret;
1650 }
1651
1652
1653 /**
1654 * Get the current card status.
1655 *
1656 * This must be freed using freeCardStatus.
1657 * @return: On success returns RIL_E_SUCCESS
1658 */
1659 static int getCardStatus(RIL_CardStatus **pp_card_status) {
1660 static RIL_AppStatus app_status_array[] = {
1661 // SIM_ABSENT = 0
1662 { RIL_APPTYPE_UNKNOWN, RIL_APPSTATE_UNKNOWN, RIL_PERSOSUBSTATE_UNKNOWN,
1663 NULL, NULL, 0, RIL_PINSTATE_UNKNOWN, RIL_PINSTATE_UNKNOWN },
1664 // SIM_NOT_READY = 1
1665 { RIL_APPTYPE_SIM, RIL_APPSTATE_DETECTED, RIL_PERSOSUBSTATE_UNKNOWN,
1666 NULL, NULL, 0, RIL_PINSTATE_UNKNOWN, RIL_PINSTATE_UNKNOWN },
1667 // SIM_READY = 2
1668 { RIL_APPTYPE_SIM, RIL_APPSTATE_READY, RIL_PERSOSUBSTATE_READY,
1669 NULL, NULL, 0, RIL_PINSTATE_UNKNOWN, RIL_PINSTATE_UNKNOWN },
1670 // SIM_PIN = 3
1671 { RIL_APPTYPE_SIM, RIL_APPSTATE_PIN, RIL_PERSOSUBSTATE_UNKNOWN,
1672 NULL, NULL, 0, RIL_PINSTATE_ENABLED_NOT_VERIFIED, RIL_PINSTATE_UNKNOWN },
1673 // SIM_PUK = 4
1674 { RIL_APPTYPE_SIM, RIL_APPSTATE_PUK, RIL_PERSOSUBSTATE_UNKNOWN,
1675 NULL, NULL, 0, RIL_PINSTATE_ENABLED_BLOCKED, RIL_PINSTATE_UNKNOWN },
1676 // SIM_NETWORK_PERSONALIZATION = 5
1677 { RIL_APPTYPE_SIM, RIL_APPSTATE_SUBSCRIPTION_PERSO, RIL_PERSOSUBSTATE_SIM_NETWORK,
1678 NULL, NULL, 0, RIL_PINSTATE_ENABLED_NOT_VERIFIED, RIL_PINSTATE_UNKNOWN }
1679 };
1680 RIL_CardState card_state;
1681 int num_apps;
1682
1683 int sim_status = getSIMStatus();
1684 if (sim_status == SIM_ABSENT) {
1685 card_state = RIL_CARDSTATE_ABSENT;
1686 num_apps = 0;
1687 } else {
1688 card_state = RIL_CARDSTATE_PRESENT;
1689 num_apps = 1;
1690 }
1691
1692 // Allocate and initialize base card status.
1693 RIL_CardStatus *p_card_status = malloc(sizeof(RIL_CardStatus));
1694 p_card_status->card_state = card_state;
1695 p_card_status->universal_pin_state = RIL_PINSTATE_UNKNOWN;
1696 p_card_status->gsm_umts_subscription_app_index = RIL_CARD_MAX_APPS;
1697 p_card_status->cdma_subscription_app_index = RIL_CARD_MAX_APPS;
1698 p_card_status->num_applications = num_apps;
1699
1700 // Initialize application status
1701 int i;
1702 for (i = 0; i < RIL_CARD_MAX_APPS; i++) {
1703 p_card_status->applications[i] = app_status_array[SIM_ABSENT];
1704 }
1705
1706 // Pickup the appropriate application status
1707 // that reflects sim_status for gsm.
1708 if (num_apps != 0) {
1709 // Only support one app, gsm
1710 p_card_status->num_applications = 1;
1711 p_card_status->gsm_umts_subscription_app_index = 0;
1712
1713 // Get the correct app status
1714 p_card_status->applications[0] = app_status_array[sim_status];
1715 }
1716
1717 *pp_card_status = p_card_status;
1718 return RIL_E_SUCCESS;
1719 }
1720
1721 /**
1722 * Free the card status returned by getCardStatus
1723 */
1724 static void freeCardStatus(RIL_CardStatus *p_card_status) {
1725 free(p_card_status);
1726 }
1727
1728 /**
1729 * SIM ready means any commands that access the SIM will work, including:
1730 * AT+CPIN, AT+CSMS, AT+CNMI, AT+CRSM
1731 * (all SMS-related commands)
1732 */
1733
1734 static void pollSIMState (void *param)
1735 {
1736 ATResponse *p_response;
1737 int ret;
1738
1739 if (sState != RADIO_STATE_SIM_NOT_READY) {
1740 // no longer valid to poll
1741 return;
1742 }
1743
1744 switch(getSIMStatus()) {
1745 case SIM_ABSENT:
1746 case SIM_PIN:
1747 case SIM_PUK:
1748 case SIM_NETWORK_PERSONALIZATION:
1749 default:
1750 setRadioState(RADIO_STATE_SIM_LOCKED_OR_ABSENT);
1751 return;
1752
1753 case SIM_NOT_READY:
1754 RIL_requestTimedCallback (pollSIMState, NULL, &TIMEVAL_SIMPOLL);
1755 return;
1756
1757 case SIM_READY:
1758 setRadioState(RADIO_STATE_SIM_READY);
1759 return;
1760 }
1761 }
1762
1763 /** returns 1 if on, 0 if off, and -1 on error */
1764 static int isRadioOn()
1765 {
1766 ATResponse *p_response = NULL;
1767 int err;
1768 char *line;
1769 char ret;
1770
1771 err = at_send_command_singleline("AT+CFUN?", "+CFUN:", &p_response);
1772
1773 if (err < 0 || p_response->success == 0) {
1774 // assume radio is off
1775 goto error;
1776 }
1777
1778 line = p_response->p_intermediates->line;
1779
1780 err = at_tok_start(&line);
1781 if (err < 0) goto error;
1782
1783 err = at_tok_nextbool(&line, &ret);
1784 if (err < 0) goto error;
1785
1786 at_response_free(p_response);
1787
1788 return (int)ret;
1789
1790 error:
1791
1792 at_response_free(p_response);
1793 return -1;
1794 }
1795
1796 /**
1797 * Initialize everything that can be configured while we're still in
1798 * AT+CFUN=0
1799 */
1800 static void initializeCallback(void *param)
1801 {
1802 ATResponse *p_response = NULL;
1803 int err;
1804
1805 setRadioState (RADIO_STATE_OFF);
1806
1807 at_handshake();
1808
1809 /* note: we don't check errors here. Everything important will
1810 be handled in onATTimeout and onATReaderClosed */
1811
1812 /* atchannel is tolerant of echo but it must */
1813 /* have verbose result codes */
1814 at_send_command("ATE0Q0V1", NULL);
1815
1816 /* No auto-answer */
1817 at_send_command("ATS0=0", NULL);
1818
1819 /* Extended errors */
1820 at_send_command("AT+CMEE=1", NULL);
1821
1822 /* Network registration events */
1823 err = at_send_command("AT+CREG=2", &p_response);
1824
1825 /* some handsets -- in tethered mode -- don't support CREG=2 */
1826 if (err < 0 || p_response->success == 0) {
1827 at_send_command("AT+CREG=1", NULL);
1828 }
1829
1830 at_response_free(p_response);
1831
1832 /* GPRS registration events */
1833 at_send_command("AT+CGREG=1", NULL);
1834
1835 /* Call Waiting notifications */
1836 at_send_command("AT+CCWA=1", NULL);
1837
1838 /* Alternating voice/data off */
1839 at_send_command("AT+CMOD=0", NULL);
1840
1841 /* Not muted */
1842 at_send_command("AT+CMUT=0", NULL);
1843
1844 /* +CSSU unsolicited supp service notifications */
1845 at_send_command("AT+CSSN=0,1", NULL);
1846
1847 /* no connected line identification */
1848 at_send_command("AT+COLP=0", NULL);
1849
1850 /* HEX character set */
1851 at_send_command("AT+CSCS=\"HEX\"", NULL);
1852
1853 /* USSD unsolicited */
1854 at_send_command("AT+CUSD=1", NULL);
1855
1856 /* Enable +CGEV GPRS event notifications, but don't buffer */
1857 at_send_command("AT+CGEREP=1,0", NULL);
1858
1859 /* SMS PDU mode */
1860 at_send_command("AT+CMGF=0", NULL);
1861
1862 #ifdef USE_TI_COMMANDS
1863
1864 at_send_command("AT%CPI=3", NULL);
1865
1866 /* TI specific -- notifications when SMS is ready (currently ignored) */
1867 at_send_command("AT%CSTAT=1", NULL);
1868
1869 #endif /* USE_TI_COMMANDS */
1870
1871
1872 /* assume radio is off on error */
1873 if (isRadioOn() > 0) {
1874 setRadioState (RADIO_STATE_SIM_NOT_READY);
1875 }
1876 }
1877
1878 static void waitForClose()
1879 {
1880 pthread_mutex_lock(&s_state_mutex);
1881
1882 while (s_closed == 0) {
1883 pthread_cond_wait(&s_state_cond, &s_state_mutex);
1884 }
1885
1886 pthread_mutex_unlock(&s_state_mutex);
1887 }
1888
1889 /**
1890 * Called by atchannel when an unsolicited line appears
1891 * This is called on atchannel's reader thread. AT commands may
1892 * not be issued here
1893 */
1894 static void onUnsolicited (const char *s, const char *sms_pdu)
1895 {
1896 char *line = NULL;
1897 int err;
1898
1899 /* Ignore unsolicited responses until we're initialized.
1900 * This is OK because the RIL library will poll for initial state
1901 */
1902 if (sState == RADIO_STATE_UNAVAILABLE) {
1903 return;
1904 }
1905
1906 if (strStartsWith(s, "%CTZV:")) {
1907 /* TI specific -- NITZ time */
1908 char *response;
1909
1910 line = strdup(s);
1911 at_tok_start(&line);
1912
1913 err = at_tok_nextstr(&line, &response);
1914
1915 if (err != 0) {
1916 LOGE("invalid NITZ line %s\n", s);
1917 } else {
1918 RIL_onUnsolicitedResponse (
1919 RIL_UNSOL_NITZ_TIME_RECEIVED,
1920 response, strlen(response));
1921 }
1922 } else if (strStartsWith(s,"+CRING:")
1923 || strStartsWith(s,"RING")
1924 || strStartsWith(s,"NO CARRIER")
1925 || strStartsWith(s,"+CCWA")
1926 ) {
1927 RIL_onUnsolicitedResponse (
1928 RIL_UNSOL_RESPONSE_CALL_STATE_CHANGED,
1929 NULL, 0);
1930 #ifdef WORKAROUND_FAKE_CGEV
1931 RIL_requestTimedCallback (onDataCallListChanged, NULL, NULL); //TODO use new function
1932 #endif /* WORKAROUND_FAKE_CGEV */
1933 } else if (strStartsWith(s,"+CREG:")
1934 || strStartsWith(s,"+CGREG:")
1935 ) {
1936 RIL_onUnsolicitedResponse (
1937 RIL_UNSOL_RESPONSE_NETWORK_STATE_CHANGED,
1938 NULL, 0);
1939 #ifdef WORKAROUND_FAKE_CGEV
1940 RIL_requestTimedCallback (onDataCallListChanged, NULL, NULL);
1941 #endif /* WORKAROUND_FAKE_CGEV */
1942 } else if (strStartsWith(s, "+CMT:")) {
1943 RIL_onUnsolicitedResponse (
1944 RIL_UNSOL_RESPONSE_NEW_SMS,
1945 sms_pdu, strlen(sms_pdu));
1946 } else if (strStartsWith(s, "+CDS:")) {
1947 RIL_onUnsolicitedResponse (
1948 RIL_UNSOL_RESPONSE_NEW_SMS_STATUS_REPORT,
1949 sms_pdu, strlen(sms_pdu));
1950 } else if (strStartsWith(s, "+CGEV:")) {
1951 /* Really, we can ignore NW CLASS and ME CLASS events here,
1952 * but right now we don't since extranous
1953 * RIL_UNSOL_DATA_CALL_LIST_CHANGED calls are tolerated
1954 */
1955 /* can't issue AT commands here -- call on main thread */
1956 RIL_requestTimedCallback (onDataCallListChanged, NULL, NULL);
1957 #ifdef WORKAROUND_FAKE_CGEV
1958 } else if (strStartsWith(s, "+CME ERROR: 150")) {
1959 RIL_requestTimedCallback (onDataCallListChanged, NULL, NULL);
1960 #endif /* WORKAROUND_FAKE_CGEV */
1961 }
1962 }
1963
1964 /* Called on command or reader thread */
1965 static void onATReaderClosed()
1966 {
1967 LOGI("AT channel closed\n");
1968 at_close();
1969 s_closed = 1;
1970
1971 setRadioState (RADIO_STATE_UNAVAILABLE);
1972 }
1973
1974 /* Called on command thread */
1975 static void onATTimeout()
1976 {
1977 LOGI("AT channel timeout; closing\n");
1978 at_close();
1979
1980 s_closed = 1;
1981
1982 /* FIXME cause a radio reset here */
1983
1984 setRadioState (RADIO_STATE_UNAVAILABLE);
1985 }
1986
1987 static void usage(char *s)
1988 {
1989 #ifdef RIL_SHLIB
1990 fprintf(stderr, "reference-ril requires: -p <tcp port> or -d /dev/tty_device\n");
1991 #else
1992 fprintf(stderr, "usage: %s [-p <tcp port>] [-d /dev/tty_device]\n", s);
1993 exit(-1);
1994 #endif
1995 }
1996
1997 static void *
1998 mainLoop(void *param)
1999 {
2000 int fd;
2001 int ret;
2002
2003 AT_DUMP("== ", "entering mainLoop()", -1 );
2004 at_set_on_reader_closed(onATReaderClosed);
2005 at_set_on_timeout(onATTimeout);
2006
2007 for (;;) {
2008 fd = -1;
2009 while (fd < 0) {
2010 if (s_port > 0) {
2011 fd = socket_loopback_client(s_port, SOCK_STREAM);
2012 } else if (s_device_socket) {
2013 if (!strcmp(s_device_path, "/dev/socket/qemud")) {
2014 /* Qemu-specific control socket */
2015 fd = socket_local_client( "qemud",
2016 ANDROID_SOCKET_NAMESPACE_RESERVED,
2017 SOCK_STREAM );
2018 if (fd >= 0 ) {
2019 char answer[2];
2020
2021 if ( write(fd, "gsm", 3) != 3 ||
2022 read(fd, answer, 2) != 2 ||
2023 memcmp(answer, "OK", 2) != 0)
2024 {
2025 close(fd);
2026 fd = -1;
2027 }
2028 }
2029 }
2030 else
2031 fd = socket_local_client( s_device_path,
2032 ANDROID_SOCKET_NAMESPACE_FILESYSTEM,
2033 SOCK_STREAM );
2034 } else if (s_device_path != NULL) {
2035 fd = open (s_device_path, O_RDWR);
2036 if ( fd >= 0 && !memcmp( s_device_path, "/dev/ttyS", 9 ) ) {
2037 /* disable echo on serial ports */
2038 struct termios ios;
2039 tcgetattr( fd, &ios );
2040 ios.c_lflag = 0; /* disable ECHO, ICANON, etc... */
2041 tcsetattr( fd, TCSANOW, &ios );
2042 }
2043 }
2044
2045 if (fd < 0) {
2046 perror ("opening AT interface. retrying...");
2047 sleep(10);
2048 /* never returns */
2049 }
2050 }
2051
2052 s_closed = 0;
2053 ret = at_open(fd, onUnsolicited);
2054
2055 if (ret < 0) {
2056 LOGE ("AT error %d on at_open\n", ret);
2057 return 0;
2058 }
2059
2060 RIL_requestTimedCallback(initializeCallback, NULL, &TIMEVAL_0);
2061
2062 // Give initializeCallback a chance to dispatched, since
2063 // we don't presently have a cancellation mechanism
2064 sleep(1);
2065
2066 waitForClose();
2067 LOGI("Re-opening after close");
2068 }
2069 }
2070
2071 #ifdef RIL_SHLIB
2072
2073 pthread_t s_tid_mainloop;
2074
2075 const RIL_RadioFunctions *RIL_Init(const struct RIL_Env *env, int argc, char **argv)
2076 {
2077 int ret;
2078 int fd = -1;
2079 int opt;
2080 pthread_attr_t attr;
2081
2082 s_rilenv = env;
2083
2084 while ( -1 != (opt = getopt(argc, argv, "p:d:s:"))) {
2085 switch (opt) {
2086 case 'p':
2087 s_port = atoi(optarg);
2088 if (s_port == 0) {
2089 usage(argv[0]);
2090 return NULL;
2091 }
2092 LOGI("Opening loopback port %d\n", s_port);
2093 break;
2094
2095 case 'd':
2096 s_device_path = optarg;
2097 LOGI("Opening tty device %s\n", s_device_path);
2098 break;
2099
2100 case 's':
2101 s_device_path = optarg;
2102 s_device_socket = 1;
2103 LOGI("Opening socket %s\n", s_device_path);
2104 break;
2105
2106 default:
2107 usage(argv[0]);
2108 return NULL;
2109 }
2110 }
2111
2112 if (s_port < 0 && s_device_path == NULL) {
2113 usage(argv[0]);
2114 return NULL;
2115 }
2116
2117 pthread_attr_init (&attr);
2118 pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
2119 ret = pthread_create(&s_tid_mainloop, &attr, mainLoop, NULL);
2120
2121 return &s_callbacks;
2122 }
2123 #else /* RIL_SHLIB */
2124 int main (int argc, char **argv)
2125 {
2126 int ret;
2127 int fd = -1;
2128 int opt;
2129
2130 while ( -1 != (opt = getopt(argc, argv, "p:d:"))) {
2131 switch (opt) {
2132 case 'p':
2133 s_port = atoi(optarg);
2134 if (s_port == 0) {
2135 usage(argv[0]);
2136 }
2137 LOGI("Opening loopback port %d\n", s_port);
2138 break;
2139
2140 case 'd':
2141 s_device_path = optarg;
2142 LOGI("Opening tty device %s\n", s_device_path);
2143 break;
2144
2145 case 's':
2146 s_device_path = optarg;
2147 s_device_socket = 1;
2148 LOGI("Opening socket %s\n", s_device_path);
2149 break;
2150
2151 default:
2152 usage(argv[0]);
2153 }
2154 }
2155
2156 if (s_port < 0 && s_device_path == NULL) {
2157 usage(argv[0]);
2158 }
2159
2160 RIL_register(&s_callbacks);
2161
2162 mainLoop(NULL);
2163
2164 return 0;
2165 }
2166
2167 #endif /* RIL_SHLIB */
2168