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