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