OSDN Git Service

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