OSDN Git Service

Remove STOP SHIP logs and comments from ril.cpp.
[android-x86/hardware-ril.git] / reference-ril / reference-ril.c
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
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  */
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 */
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 */
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
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
286 static void onDataCallListChanged(void *param)
287 {
288     requestOrSendDataCallList(NULL);
289 }
290
291 static void requestDataCallList(void *data, size_t datalen, RIL_Token t)
292 {
293     requestOrSendDataCallList(&t);
294 }
295
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
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
470 static void sendCallStateChanged(void *param)
471 {
472     RIL_onUnsolicitedResponse (
473         RIL_UNSOL_RESPONSE_CALL_STATE_CHANGED,
474         NULL, 0);
475 }
476
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 */