OSDN Git Service

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