OSDN Git Service

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